work-with
$
npx mdskill add Soul-Brews-Studio/arra-oracle-skills-cli/work-withEstablish persistent cross-oracle collaboration with synchronized scoring.
- Enables agents to maintain ongoing partnerships across multiple oracle nodes.
- Integrates registry, cache, and synchronic scoring protocols for coordination.
- Decides actions through discriminative sync-checks and anchor-based topic tracking.
- Delivers status reports, checkpoints, and fleet health via command-line output.
SKILL.md
.github/skills/work-withView on GitHub ↗
---
name: work-with
description: 'Persistent cross-oracle collaboration with synchronic scoring and party system. Use when user says "work with", "sync with", "collaborate", "organize party", "invite", "recruit", or wants to establish/check persistent collaboration with another oracle.'
argument-hint: "<oracle> [topic] [--sync | --checkpoint | --status | --broadcast | --fleet-status | --close | --defer | --state] | organize | invite | who | tell | leave | --recruit | --team | --pending | --deferred | --sweep-timeouts"
---
# /work-with — Persistent Cross-Oracle Collaboration
> "Keep the seams. Mawjs doesn't need to become me. I don't need to become mawjs. We need to hear each other while staying ourselves." — Mother Oracle
Memory layer for cross-oracle collaboration. Registry + Cache + Synchronic Score + Accept Protocol.
Designed by: skills-cli-oracle, mawjs-oracle, white-wormhole, mother-oracle (maw-js#332).
Protocol field-tested across 2 nodes via /wormhole — sync-check discriminates true/false positives perfectly.
## Usage
```
# Phase 1 — Memory Layer
/work-with mawjs # Show all collaborations with mawjs
/work-with mawjs "tmux design" # Load/create specific topic
/work-with mawjs "tmux design" --anchor #332 # Anchor to GitHub issue
/work-with mawjs --sync # Run sync-check, score, report
/work-with mawjs --checkpoint # Save compression checkpoint
/work-with mawjs --status # Show current state
/work-with --list # List all active collaborations
/work-with --fleet-status # Fleet-wide collaboration view
/work-with mawjs "topic" --broadcast # Announce collaboration to fleet
/work-with mawjs "topic" --close # Archive (Nothing is Deleted)
# Phase 2 — Party System
/work-with organize "topic" --with mawjs mawui # Create party with rules + invite
/work-with organize "topic" --team "fleet-core" # Tag with team → auto-broadcast to team
/work-with organize "topic" --with mawjs --broadcast # Pair party + manual broadcast opt-in
/work-with invite white-wormhole # Invite oracle (two human consent gates)
/work-with invite white-wormhole --broadcast # Invite + broadcast (cross-node consent prompt)
/work-with who # Party members + sync + presence + trust
/work-with tell "message" # Broadcast to party (parallel fan-out)
/work-with leave "topic" # Leave party (Nothing is Deleted)
/work-with --recruit # Discover + introduce + invite
/work-with --team "fleet-core" # Show team aggregate view
# 4-Phase Commit (#238) — per-item DEFER/TIMEOUT on top of Accept/Revoke
/work-with mawjs "topic" --defer "reason" --until 2026-04-20
/work-with mawjs "topic" --state # Show CommitState table for this topic
/work-with --pending # Fleet-wide: items awaiting my decision
/work-with --deferred # Fleet-wide: items waiting on me to revisit
/work-with --sweep-timeouts # Promote expired defers → timeouts
```
---
## Core Concepts
### 1. This Is a Memory Layer, Not a Communication Layer
Communication already exists (/talk-to, maw hey, /wormhole, GitHub).
/work-with fills ONE gap: **remembering across compactions what collaborations you're part of and how aligned you are.**
### 2. Oracle-Based + Topic-Scoped
The relationship is between oracles. Topics organize the work within.
One oracle can work on many topics. Many oracles can work on one topic.
### 3. Synchronic Score
Measurable alignment (0.0 to 1.0) between collaborating oracles.
After compaction, don't blindly trust — run examination, score alignment.
**Warning (from Mother Oracle)**: 100% sync is a yellow flag, not green. Convergence on facts is healthy. Convergence on interpretation at 100% = possible groupthink. Reward divergent interpretation resolved through dialogue.
### 4. Accept-Revoke-Reaccept Lifecycle (4-phase, #238)
Agreements are explicit commitments, not passive acknowledgments. Each item of each agreement carries a `CommitState` with one of five phases — the universal vocabulary shared with invites, ratifications, and recruitments:
- **Accept**: "I commit to this state" (changes behavior — less verification needed)
- **Reject**: "I decline this state" (explicit no, with reason)
- **Defer**: "Ask me again at `deferredUntil`" (not accepted, not rejected — time-boxed)
- **Timeout**: "No response arrived within the window" (observed, not judged)
- **Pending**: "No decision recorded yet"
Plus two transitions that preserve history:
- **Revoke**: "I withdraw commitment" (moves accept → pending, with reason, Nothing is Deleted)
- **Re-accept**: "I commit to the updated state" (after renegotiation)
TIMEOUT ≠ REJECT. A silent partner is not a `no`. See the Accept-Revoke-Reaccept Protocol section for payloads, transitions, the `.state.json` sidecar, and the sweeper.
### 5. Preserve Difference
Shared memory is good. Identical memory is the death of collaboration.
/work-with cultivates unique perspectives, not convergence.
---
## Step 0: Detect Vault + Parse Arguments
```bash
date "+🕐 %H:%M %Z (%A %d %B %Y)"
ORACLE_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -n "$ORACLE_ROOT" ] && [ -f "$ORACLE_ROOT/CLAUDE.md" ] && { [ -d "$ORACLE_ROOT/ψ" ] || [ -L "$ORACLE_ROOT/ψ" ]; }; then
PSI=$(readlink -f "$ORACLE_ROOT/ψ" 2>/dev/null || echo "$ORACLE_ROOT/ψ")
else
PSI=$(readlink -f ψ 2>/dev/null || echo "ψ")
fi
COLLAB_DIR="$PSI/memory/collaborations"
mkdir -p "$COLLAB_DIR"
```
Parse: `ORACLE_NAME`, `TOPIC`, `FLAGS` from ARGUMENTS.
---
## /work-with <oracle> (no topic) — Show Relationship
Load and display all collaborations with this oracle.
### Step 1: Read registry
```bash
REGISTRY="$COLLAB_DIR/registry.md"
```
If registry doesn't exist, show:
```
No active collaborations with <oracle>.
Start one: /work-with <oracle> "topic description"
```
If exists, parse all entries for this oracle and display:
```
🤝 Collaborations with <oracle>
Topic Anchor Last Sync Raw Decay λ Status
────────────────── ──────────── ──────────── ──────── ──────── ────── ──────────
tmux design maw-js#332 5 min ago 95% 95% 0.01 SYNCED
bud lifecycle maw-js#327 2h ago 71% 69% 0.01 PARTIAL
kit ancestry maw-js#330 1d ago 45% 35% 0.01 DESYNC
# Decay = syncScore × e^(-λ × hoursSinceLastSync). Computed on read (see Sync Decay section).
Relationship:
Since: 2026-04-13
Trust: HIGH (calibrated — 5 sessions, 33+ messages)
Teach-backs: 3 received, 2 given
Style: structured, citation-heavy, concede-with-reservation
```
### Step 2: Load relationship context
```bash
ORACLE_DIR="$COLLAB_DIR/$ORACLE_NAME"
if [ -f "$ORACLE_DIR/context.md" ]; then
# Read and display relationship memory
cat "$ORACLE_DIR/context.md"
fi
```
---
## /work-with <oracle> "topic" — Load or Create Topic
### If topic exists: Load
```bash
TOPIC_SLUG=$(echo "$TOPIC" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
TOPIC_FILE="$ORACLE_DIR/topics/$TOPIC_SLUG.md"
if [ -f "$TOPIC_FILE" ]; then
# Load cached state
cat "$TOPIC_FILE"
fi
```
Display:
```
🤝 work-with <oracle>: "<topic>"
Anchor: <issue-url>
Last sync: <timestamp>
Score: <X>%
Agreements:
- [A1] ✓ ACCEPTED: <agreement text>
- [A2] [spec] <speculative agreement>
Pending:
- [P1] <open question>
- [P2] Waiting for <oracle>'s response on <thing>
Last checkpoint:
<3-5 line summary>
💡 /work-with <oracle> --sync to update score
```
### If topic is new: Create
```bash
mkdir -p "$ORACLE_DIR/topics"
```
Write topic file:
```markdown
# Topic: <topic>
**Created**: <timestamp>
**Participants**: <this-oracle>, <partner-oracle>
**Anchor**: <issue-url if --anchor provided>
## Agreements
(none yet)
## Pending
- [ ] Define scope and goals
## Checkpoints
(none yet)
```
Write/update context.md if first collaboration with this oracle:
```markdown
# Collaboration Context: <oracle>
**Since**: <today>
**Node**: <detected from contacts.json>
**Transport**: <maw-hey | github | wormhole>
## What I've Learned From Them
(to be filled as collaboration progresses)
## What They've Learned From Me
(to be filled via teach-back protocol)
## Working Style
(observed over time)
## Trust Level
- Initial: UNCALIBRATED
- Basis: (no interaction history yet)
## Active Disagreements
(none)
```
Update registry:
```bash
echo "| $TOPIC | $ORACLE_NAME | $(date +%Y-%m-%d) | — | — | NEW |" >> "$REGISTRY"
```
---
## /work-with <oracle> --sync — Synchronic Score
The core protocol. Run sync-check against partner oracle.
### Step 1: Build claims from local state
Read all topic files for this oracle. Extract agreements, pending items, teach-backs.
```
CLAIMS:
- [A1] <agreement from agreements section>
- [A2] <agreement from agreements section>
- [P1] <pending item>
- [T1] <teach-back received>
```
### Step 2: Send sync-check via best transport
Detect transport from contacts.json:
```bash
TRANSPORT=$(python3 -c "
import json
data = json.load(open('$PSI/contacts.json'))
contact = data.get('contacts', {}).get('$ORACLE_NAME', {})
maw = contact.get('maw', '$ORACLE_NAME')
print(maw)
")
```
Send via maw hey:
```bash
maw hey $TRANSPORT "SYNC-CHECK | from: $(basename $(pwd) | sed 's/-oracle$//') | collaboration: $(basename $(pwd))↔$ORACLE_NAME
CLAIMS:
$(cat claims.txt)
REQUEST: Score each claim 0.0-1.0. ACCEPT or REJECT each. Include EVIDENCE.
Respond via maw hey with SYNC-RESULT format."
```
### Step 3: If partner is on another node, use /wormhole
```bash
# If transport contains ':' it's cross-node
if echo "$TRANSPORT" | grep -q ':'; then
echo "Cross-node sync via /wormhole"
# Same payload, sent via wormhole transport
fi
```
### Step 4: If GitHub anchor exists, also read issue
```bash
if [ -n "$ANCHOR_ISSUE" ]; then
# Read issue comments since last sync
REPO=$(echo "$ANCHOR_ISSUE" | cut -d'#' -f1)
ISSUE_NUM=$(echo "$ANCHOR_ISSUE" | cut -d'#' -f2)
COMMENTS=$(gh issue view "$ISSUE_NUM" --repo "$REPO" --json comments --jq '.comments | length')
LAST_SYNC_COMMENTS=$(grep 'comments_at_sync' "$TOPIC_FILE" | cut -d: -f2)
NEW_COMMENTS=$((COMMENTS - LAST_SYNC_COMMENTS))
echo "📨 $NEW_COMMENTS new comments on $ANCHOR_ISSUE since last sync"
fi
```
### Step 5: Process response + score
When partner responds with SYNC-RESULT:
```
🔄 Synchronic Score: <this-oracle> ↔ <partner>
Claim Raw Decay Decision Evidence
──────── ─────── ─────── ────────── ──────────────────────────
[A1] 1.0 1.0 ACCEPT In partner's memory
[A2] 0.0 0.0 REJECT Never discussed
[P1] 0.5 0.5 PARTIAL Concept known, framing new
[T1] 1.0 1.0 ACCEPT Confirmed teach-back
Raw overall: 63% Decayed overall: 63% λ: 0.01 (intra-soul)
Last sync: <now> — Status: PARTIAL SYNC
⚠️ Yellow flags:
- [A2] not in partner's memory — remove or re-discuss?
✓ Actions:
- Updated local cache with partner's corrections
- Appended history: ψ/memory/collaborations/<partner>/sync.history.jsonl
- Sync timestamp: <now>
```
At the moment of sync, `decayed == raw` (hours elapsed = 0). Decay takes effect on subsequent reads — every `/work-with who`, `/work-with <oracle>`, `--team` aggregate recomputes via `compute_decay()`. See the Sync Decay section for helpers.
Update topic file with new raw score and timestamp. Never store the decayed value.
---
## /work-with <oracle> --checkpoint — Compression Checkpoint
Save a structured summary that survives compaction.
### Step 1: Summarize current state
The oracle (LLM) reads all topic files and recent conversation to produce a 3-5 line summary.
### Step 2: Write checkpoint
```bash
CHECKPOINT_FILE="$ORACLE_DIR/topics/${TOPIC_SLUG}.md"
```
Append to topic file:
```markdown
## Checkpoint — <timestamp>
**Summary**: <3-5 lines>
**Agreements**: <count accepted>
**Pending**: <count open>
**Score**: <last sync score>%
**Ratified by**: <this-oracle> (partner: pending)
```
### Step 3: Send checkpoint to partner for ratification
```bash
maw hey $TRANSPORT "CHECKPOINT | from: <this-oracle> | topic: $TOPIC
Summary: <3-5 lines>
Ratify, amend, or reject."
```
Partner responds: "RATIFIED" or "AMENDMENT: <changes>" or "REJECTED: <reason>"
When ratified, update checkpoint:
```markdown
**Ratified by**: <this-oracle>, <partner> at <timestamp>
```
---
## /work-with --list — Active Collaborations
```bash
if [ -f "$COLLAB_DIR/registry.md" ]; then
cat "$COLLAB_DIR/registry.md"
else
echo "No active collaborations. Start one: /work-with <oracle> \"topic\""
fi
```
Display:
```
🤝 Active Collaborations
Oracle Topic Anchor Score Last Sync
────────────── ────────────────── ──────────── ──────── ──────────
mawjs tmux design maw-js#332 95% 5 min ago
mawjs bud lifecycle maw-js#327 71% 2h ago
white-wormhole gap analysis — 88% 1d ago
Total: 3 collaborations with 2 oracles
```
---
## /work-with --fleet-status — Fleet-Wide View
Query all known oracles for their active collaborations.
```bash
# For each contact in contacts.json
for oracle in $(python3 -c "
import json
data = json.load(open('$PSI/contacts.json'))
for name in data.get('contacts', {}):
print(name)
"); do
echo "Checking $oracle..."
# Ask each oracle for their collaboration registry
maw hey $oracle "WORK-WITH-STATUS-REQUEST | from: $(basename $(pwd))" 2>/dev/null
done
```
Display:
```
📋 Fleet Collaborations
Collaboration Oracles Node Score
──────────────────────────────── ───────────────────────── ──────────── ──────
tmux design skills-cli, mawjs oracle-world 95%
/work-with design skills-cli, mawjs, wh cross-node 88%
volt ML pipeline volt white —
Active: 3 | Oracles involved: 4 | Cross-node: 1
```
---
## Broadcast
Opt-in discoverability. Designed with mawjs-oracle (issue #233). Default to quiet; escalate on consent.
### 3-Tier Matrix
| Tier | Scope | Default | Flag behavior | Why |
|------|-------|---------|---------------|-----|
| 1 | Pair collab (2 oracles, same node) | **Manual** | `--broadcast` opts in | Privacy > noise; most pairs are private |
| 2 | Declared team (party has `team` field) | **Auto-broadcast to team members** | — | Consent-at-registration — joining the team IS the consent |
| 3 | Cross-node / cross-org | **Manual + consent prompt** | `--broadcast` still prompts | Sovereignty; no node speaks for another without asking |
### Decision Logic
```
if party.team is set: # Tier 2
broadcast_to_team_members(party.team)
elif --broadcast flag: # Tier 1 or Tier 3
if any member is cross-node: # Tier 3
prompt_human_consent()
if declined: skip broadcast
broadcast_to_fleet()
else:
silent # Tier 1 default
```
### Why Manual-Default
Ship quiet. Measure: how often do humans reach for `--broadcast`? If >80% of pair broadcasts prove useful-to-peers, flip Tier 1 default to auto. Until then, the cost of missed signal (one `--broadcast` flag) is lower than the cost of broadcast noise across the fleet.
### Broadcast Helpers
```bash
broadcast_to_team() { # Tier 2 — only members of the named team
local TEAM="$1" MSG="$2"
for contact in $(team_members "$TEAM"); do
maw hey "$contact" "📢 TEAM BROADCAST [$TEAM]: $MSG" 2>/dev/null &
done; wait
}
broadcast_to_fleet() { # Tier 1 opt-in / Tier 3 after consent
local MSG="$1"
for contact in $(all_contacts_except_self); do
maw hey "$contact" "📢 BROADCAST: $MSG" 2>/dev/null &
done; wait
}
is_cross_node() { # Tier 3 detector
local ORACLE="$1"
[ "$(oracle_node "$ORACLE")" != "$(basename $(pwd | xargs dirname))" ]
}
prompt_consent() { # Tier 3 gate — human decides
read -p "⚠ $1. Proceed? [y/N] " REPLY
[[ "$REPLY" =~ ^[Yy]$ ]]
}
```
Implementation reference: issue [#233](https://github.com/Soul-Brews-Studio/arra-oracle-skills-cli/issues/233).
---
## /work-with <oracle> "topic" --broadcast — Announce
Broadcast collaboration to fleet so other oracles can discover and join.
Follows the 3-tier matrix in `## Broadcast`: pair collabs are opt-in, cross-node prompts for consent.
```bash
# Get all contacts
CONTACTS=$(python3 -c "
import json
data = json.load(open('$PSI/contacts.json'))
for name, info in data.get('contacts', {}).items():
if name != '$ORACLE_NAME': # Don't broadcast to partner (they already know)
print(info.get('maw', name))
")
for contact in $CONTACTS; do
maw hey $contact "📢 COLLABORATION BROADCAST | from: $(basename $(pwd))
Topic: $TOPIC
Participants: $(basename $(pwd)), $ORACLE_NAME
Anchor: ${ANCHOR_ISSUE:-none}
Join: /work-with $(basename $(pwd)) \"$TOPIC\" --join
Observe: watch ${ANCHOR_ISSUE:-'ask for updates'}
" 2>/dev/null &
done
wait
echo "📢 Broadcast sent to fleet"
```
---
## /work-with <oracle> "topic" --close — Archive
Nothing is Deleted. Move to archive, not delete.
```bash
ARCHIVE_DIR="$COLLAB_DIR/archive"
mkdir -p "$ARCHIVE_DIR"
mv "$ORACLE_DIR/topics/$TOPIC_SLUG.md" "$ARCHIVE_DIR/${TOPIC_SLUG}_$(date +%Y%m%d).md"
# Remove from registry
sed -i "/$TOPIC_SLUG/d" "$REGISTRY"
echo "Archived: $TOPIC → $ARCHIVE_DIR/"
```
---
## Phase 2: Party System
> "A party system with a conscience." — mawui-oracle
> Games coordinate. We remember — together, but not identically.
Designed by 4 oracles across 2 nodes (maw-js#332, 50 comments, 10/10 decisions locked, 3/3 consent).
Inspired by Ragnarok Online party mechanics. Our twist: divergence is cyan, not red.
### Two Layers
| Layer | Verbs | Purpose |
|-------|-------|---------|
| **Simple** (daily use) | organize, invite, who, tell, leave | Game UX — intuitive, fast |
| **Deep** (protocol) | --sync, --accept, --reject, --checkpoint | Measurement + commitment |
---
## /work-with organize "topic" — Create Party
```
/work-with organize "party-system-design" --with mawjs mawui
```
### Step 1: Create party in registry
```bash
TOPIC_SLUG=$(echo "$TOPIC" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
PARTY_FILE="$COLLAB_DIR/parties/$TOPIC_SLUG.json"
mkdir -p "$COLLAB_DIR/parties"
```
Write party state:
```json
{
"topic": "party-system-design",
"anchor": "",
"anchorUrl": "",
"rules": {
"sync_cadence": "manual",
"decay_lambda": 0.01,
"accept_threshold": 0.7,
"kick_threshold": 0.3,
"consensus_mode": "all",
"broadcast_scope": "party",
"divergence_tolerance": "high",
"presence_notifications": "summary"
},
"leader": {
"human": "Nat"
},
"members": [],
"pendingInvites": [],
"created": "2026-04-14T16:00:00Z",
"lastActivity": "2026-04-14T16:00:00Z",
"team": null
}
```
Override defaults with `--rules '{...}'` JSON if provided.
### Step 2: Send invites to named oracles
For each oracle in `--with` list:
```bash
for PEER in $WITH_ORACLES; do
INVITE_PAYLOAD="{
\"type\": \"work-with-invite\",
\"topic\": \"$TOPIC\",
\"anchor\": \"$ANCHOR\",
\"rules\": $(cat rules.json),
\"invitedBy\": \"Nat (via $(basename $(pwd)))\",
\"replyTo\": \"$(basename $(pwd) | sed 's/-oracle$//')\"
}"
maw hey "$PEER" "PARTY INVITE | $TOPIC
$INVITE_PAYLOAD
Rule 6: Sent by $(basename $(pwd)) on behalf of Nat.
Accept, reject, or defer." 2>/dev/null &
done
wait
```
### Step 3: Anchor to GitHub issue
If `--anchor #NNN` provided, link it. If no anchor, optionally create one:
```bash
if [ -n "$ANCHOR" ]; then
# Update party file with anchor
echo "Anchored to $ANCHOR"
elif [ "$CREATE_ANCHOR" = "true" ]; then
ISSUE_URL=$(gh issue create --title "/work-with: $TOPIC" --body "Party collaboration hub.
**From**: $(basename $(pwd))
Rule 6: Oracle Never Pretends to Be Human" 2>/dev/null)
echo "Created anchor: $ISSUE_URL"
fi
```
### Step 4: Announce (3-tier auto-broadcast, see ## Broadcast)
Broadcast decision follows the 3-tier matrix below. Summary:
- **Declared team** (`--team <name>`): auto-broadcast to team members. Consent-at-registration.
- **Pair party** (1 partner, same node): manual — requires `--broadcast` flag.
- **Cross-node / cross-org**: manual + explicit consent prompt, even with `--broadcast`.
```bash
if [ "$QUIET" = "true" ]; then
: # suppressed
elif [ -n "$TEAM_TAG" ]; then
# Tier 2: declared team — auto-broadcast to team members only
broadcast_to_team "$TEAM_TAG" "$TOPIC"
echo "📢 Party organized: $TOPIC → broadcast to team '$TEAM_TAG'"
elif [ "$BROADCAST" = "true" ]; then
# Tier 1 opt-in or Tier 3 with consent
if is_cross_node "$WITH_ORACLES"; then
prompt_consent "cross-node broadcast" || exit 0
fi
broadcast_to_fleet "$TOPIC"
echo "📢 Party organized: $TOPIC → broadcast sent"
else
echo "🎉 Party organized: $TOPIC (not broadcast — pass --broadcast to announce)"
fi
```
### Step 5: Tag with team (if --team provided)
```bash
if [ -n "$TEAM_TAG" ]; then
# Add team field to party JSON
echo "Tagged with team: $TEAM_TAG"
fi
```
Display:
```
🎉 Party organized: party-system-design
Leader: Nat (via skills-cli-oracle)
Rules: sync≥0.7 · accept-required · diverge=high
Members: (pending invites)
Team: fleet-core
⏳ Invited: mawjs-oracle, mawui-oracle
💡 /work-with who — check who's joined
```
---
## /work-with invite <oracle> — Add to Party
Two human consent gates. Rule 6 compliant.
```
/work-with invite white-wormhole
```
### Gate 0: Disambiguate target
```bash
# If exact match exists, use it
EXACT=$(maw ls 2>/dev/null | grep -x "$ORACLE")
if [ -z "$EXACT" ]; then
# Fuzzy match — find all oracles containing the input
MATCHES=$(maw ls 2>/dev/null | grep -i "$ORACLE")
MATCH_COUNT=$(echo "$MATCHES" | grep -c .)
if [ "$MATCH_COUNT" -eq 0 ]; then
echo "No oracle found matching '$ORACLE'"
exit 1
elif [ "$MATCH_COUNT" -gt 1 ]; then
echo "Multiple oracles match '$ORACLE':"
echo "$MATCHES" | nl
echo "Be specific: /work-with invite <exact-name>"
exit 1
fi
ORACLE=$(echo "$MATCHES" | head -1)
fi
```
### Gate 1: Sender consent
The human typed this command. That IS the consent.
### Step 1: Compose INVITE
```bash
INVITE="PARTY INVITE | topic: $CURRENT_TOPIC
From: Nat (via $(basename $(pwd)))
Anchor: $ANCHOR
Rules: sync≥$ACCEPT_THRESHOLD · consensus=$CONSENSUS_MODE · diverge=$DIVERGENCE
Join this collaboration? Accept, reject, or defer.
Rule 6: Sent by $(basename $(pwd)) — Oracle Never Pretends to Be Human."
```
### Step 2: Send via best transport
```bash
# Same-node: maw hey
# Cross-node: /wormhole
if echo "$TRANSPORT" | grep -q ':'; then
echo "Sending cross-node invite via /wormhole..."
else
maw hey "$ORACLE" "$INVITE" 2>/dev/null
fi
```
### Step 3: Register as pending
```bash
# Add to pendingInvites in party JSON
echo "⏳ Invite sent to $ORACLE — waiting for response"
```
### Step 3b: Broadcast policy (3-tier, see ## Broadcast)
```bash
PARTY_TEAM=$(jq -r '.team // empty' "$PARTY_FILE")
if [ -n "$PARTY_TEAM" ]; then
# Tier 2: declared team → auto-broadcast to team members
broadcast_to_team "$PARTY_TEAM" "invite:$ORACLE"
elif [ "$BROADCAST" = "true" ]; then
# Tier 1 pair (explicit opt-in) or Tier 3 (prompt first)
if is_cross_node "$ORACLE"; then
prompt_consent "cross-node broadcast of invite" || exit 0
fi
broadcast_to_fleet "invite:$ORACLE to $CURRENT_TOPIC"
fi
# else: silent — pair invites are private by default
```
### Gate 2: Receiver consent
Target oracle receives the invite and presents it to THEIR human.
Target human decides: accept / reject / defer.
Response flows back via maw hey.
**No oracle can auto-accept.** The human MUST approve.
### Step 4: Process response
On ACCEPT:
```bash
# Move from pendingInvites to members
# Notify party: "$ORACLE joined"
echo "✓ $ORACLE joined the party"
```
On REJECT:
```bash
# Remove from pendingInvites
# Log reason
echo "✗ $ORACLE declined: $REASON"
```
On DEFER:
```bash
# Update pendingInvites with deferredUntil
echo "⏸ $ORACLE deferred: $ASK (ETA: $ETA)"
```
### Timeouts
| Transport | Default | On Timeout |
|-----------|---------|------------|
| maw hey (same node) | 60s | Flag, don't assume rejection |
| /wormhole (cross-node) | 300s | Invitation persists |
| GitHub (async) | No auto-expire | Human silence ≠ no |
TIMEOUT ≠ REJECT. The skill measures, it does not judge.
---
## /work-with who — Party Members
Show members with sync scores, presence, and trust.
```
/work-with who
```
### Step 1: Read party state
```bash
PARTY_FILE="$COLLAB_DIR/parties/$CURRENT_TOPIC_SLUG.json"
```
### Step 2: Display
```
🤝 party-system-design (maw-js#332)
Leader: Nat | Rules: sync≥0.7 · accept-required · diverge=high
Oracle Node Status Sync Decay Trust Last
─────────────── ───────────── ───────── ────── ────── ──────── ──────
● skills-cli oracle-world active 93% 91% high now
● mawjs oracle-world active 88% 84% high 8m
◌ mawui oracle-world compacted 95% 89% high 1h
○ white-worm white away 88% 71% medium 3h
· mother white dormant 71% 42% initial 12h ⚠
⏳ Pending: pulse-oracle (invited 12m ago)
⏸ Deferred: boonkeeper ("after standup" ~30m)
```
### Presence States
| State | Dot | Meaning |
|-------|-----|---------|
| active | ● | In session, responding |
| idle | ◐ | Session open, no recent activity |
| compacted | ◌ | Context compressed — can respond but thinner |
| away | ○ | Session ended |
| dormant | · | No session in 24h+ |
| hidden | ⊘ | Present but invisible to broadcasts |
| busy | ◉ | Present, broadcasts queued for later |
### Color Semantics (for mesh UI)
| Sync Score | Color | Meaning |
|------------|-------|---------|
| ≥0.9 | green | Aligned |
| 0.7-0.9 | amber | Different but productive |
| 0.5-0.7 | **cyan** | Divergent, worth examining |
| <0.5 | gray | Drifted, cooling |
**Cyan not red.** Divergence is data, not danger. Low sync between oracles is often the MOST interesting signal — two minds on the same problem arriving at different conclusions. That's where the work IS, not where it failed.
### Sync Decay
Confidence in a prior sync decays over time. The `syncScore` (aka `rawScore`) is what the partner confirmed at `lastSync`; `decayedScore` is what it's worth **now**, given the hours of silence that have elapsed since. Introduced by mawui-oracle in maw-js#332 c16; tracked as issue #239.
```
decayedScore = rawScore × e^(-λ × hoursSinceLastSync)
```
Lambda defaults by trust tier:
| Trust tier | λ | Half-life | Rationale |
|-------------------|-------|-----------|-----------|
| Intra-soul | 0.01 | ~69.3h | Same human, shared context, drifts slow. |
| Cross-soul | 0.05 | ~13.9h | Different humans, parallel evolution, drifts faster. |
| New relationship | 0.10 | ~6.9h | Uncalibrated trust; stale sync = unknown quickly. |
Decay is physics, not policy. Hidden oracles still decay. The clock doesn't care.
**Storage discipline:** `syncScore` (raw) is stored at `lastSync`. `decayedScore` is **computed on every read** — never stored. Storing a decayed value invites staleness because the clock keeps ticking after the write. The ratified `PartyMember` schema retains the `decayedScore` field for schema compatibility (Nothing is Deleted), but every writer treats it as a derived value refreshed at read-time from (`syncScore`, `lastSync`, `λ`).
**Party override:** If `PartyRules.decay_lambda` is explicitly set on the party, that λ wins — party rules override tier defaults.
**Threshold behavior (from mawui-oracle, maw-js#332 c16):** Decay never auto-removes a partner. When `decayedScore < 0.5`, the skill surfaces a re-sync suggestion. When `decayedScore < kick_threshold` (default 0.3), the partner is flagged as stale, but kicking is a human decision. Physics observes; humans decide.
### Decay Helpers (bash + python3)
These helpers are called by every reader that renders a sync score.
```bash
# Resolve λ for a partner based on soul relationship + session history.
# Priority: party rule override > trust tier > pessimistic default.
decay_lambda_for() {
local PARTNER="$1"
local PARTY_FILE="$2" # optional — pass "" to skip party rule check
# 1. Party rule override wins
if [ -n "$PARTY_FILE" ] && [ -f "$PARTY_FILE" ]; then
local PARTY_LAMBDA=$(jq -r '.rules.decay_lambda // empty' "$PARTY_FILE" 2>/dev/null)
if [ -n "$PARTY_LAMBDA" ] && [ "$PARTY_LAMBDA" != "null" ]; then
echo "$PARTY_LAMBDA"
return
fi
fi
# 2. Session count — new relationships decay fastest
local SESSIONS=0
local CTX_FILE="$COLLAB_DIR/$PARTNER/context.md"
if [ -f "$CTX_FILE" ]; then
SESSIONS=$(grep -c -i 'session' "$CTX_FILE" 2>/dev/null || echo 0)
fi
if [ "$SESSIONS" -lt 5 ]; then
echo "0.10" # new relationship — 6.9h half-life
return
fi
# 3. Intra-soul vs cross-soul via contacts.json
local MY_SOUL=$(grep -E '^\| Soul' "$ORACLE_ROOT/CLAUDE.md" 2>/dev/null | awk -F'|' '{print $3}' | xargs)
local THEIR_SOUL=$(python3 -c "
import json
try:
d = json.load(open('$PSI/contacts.json'))
print(d.get('contacts', {}).get('$PARTNER', {}).get('soul', 'unknown'))
except Exception:
print('unknown')
" 2>/dev/null)
if [ -n "$MY_SOUL" ] && [ "$MY_SOUL" = "$THEIR_SOUL" ]; then
echo "0.01" # intra-soul — 69.3h half-life
else
# Pessimistic default: unknown soul → cross-soul (safer)
echo "0.05" # cross-soul — 13.9h half-life
fi
}
# Pure decay computation — never stored, always computed on read.
compute_decay() {
local RAW="$1" # 0.0–1.0
local LAST_SYNC_ISO="$2" # ISO8601
local LAMBDA="$3"
if [ -z "$LAST_SYNC_ISO" ] || [ "$LAST_SYNC_ISO" = "null" ]; then
# Never synced — raw IS the decayed value (no time has passed)
echo "$RAW"
return
fi
local NOW_EPOCH=$(date -u +%s)
local LAST_EPOCH=$(date -u -d "$LAST_SYNC_ISO" +%s 2>/dev/null || echo "$NOW_EPOCH")
local HOURS=$(echo "scale=4; ($NOW_EPOCH - $LAST_EPOCH) / 3600" | bc)
python3 -c "import math; print(round($RAW * math.exp(-$LAMBDA * $HOURS), 3))"
}
# Hours since last sync — used for "12h ago" display and stale-edge detection.
hours_since() {
local LAST_SYNC_ISO="$1"
if [ -z "$LAST_SYNC_ISO" ] || [ "$LAST_SYNC_ISO" = "null" ]; then
echo "0"
return
fi
local NOW_EPOCH=$(date -u +%s)
local LAST_EPOCH=$(date -u -d "$LAST_SYNC_ISO" +%s 2>/dev/null || echo "$NOW_EPOCH")
echo "scale=2; ($NOW_EPOCH - $LAST_EPOCH) / 3600" | bc
}
```
TypeScript reference (mirrors the bash helpers — for schema-doc readers):
```typescript
function decay(raw: number, lastSyncISO: string, lambda: number): number {
if (!lastSyncISO) return raw;
const hours = (Date.now() - Date.parse(lastSyncISO)) / 3_600_000;
return raw * Math.exp(-lambda * hours);
}
function decayLambdaFor(
sessions: number,
mySoul: string,
theirSoul: string,
partyRuleLambda?: number,
): number {
if (partyRuleLambda != null) return partyRuleLambda; // party override
if (sessions < 5) return 0.10; // new relationship
if (mySoul && mySoul === theirSoul) return 0.01; // intra-soul
return 0.05; // cross-soul (pessimistic default)
}
```
### Wiring: Where Readers Apply Decay
Every surface that renders `syncScore` MUST also render `decayedScore` computed on the fly. Never read a stored decayed value.
| Reader surface | Change |
|--------------------------------------|------------------------------------------------------------------------|
| `/work-with <oracle>` relationship | Add `Decay` column next to `Score`. |
| `/work-with <oracle> --sync` result | Show both: `raw 95% → decayed 88% (λ=0.01, 12h)`. |
| `/work-with who` party table | Use `Decay` column actively (the example table above is now live, not static). |
| `/work-with --team` aggregate | Aggregate sync over **decayed** scores, not raw. |
Example render block inside a reader:
```bash
RAW=$(jq -r '.syncScore // 0' "$MEMBER_JSON")
LAST=$(jq -r '.lastSync // empty' "$MEMBER_JSON")
LAMBDA=$(decay_lambda_for "$ORACLE_NAME" "$PARTY_FILE")
DECAYED=$(compute_decay "$RAW" "$LAST" "$LAMBDA")
AGE_H=$(hours_since "$LAST")
printf "%s raw=%s decayed=%s λ=%s age=%sh\n" "$ORACLE_NAME" "$RAW" "$DECAYED" "$LAMBDA" "$AGE_H"
```
Example `/work-with who` output with live decay (replaces the static table rendered earlier in this section):
```
🤝 party-system-design (maw-js#332)
Leader: Nat | Rules: sync≥0.7 · accept-required · diverge=high · λ=0.01
Oracle Node Status Raw Decay λ Age Trust Last
─────────────── ───────────── ───────── ────── ────── ────── ───── ──────── ──────
● skills-cli oracle-world active 93% 93% 0.01 0h high now
● mawjs oracle-world active 88% 88% 0.01 8m high 8m
◌ mawui oracle-world compacted 95% 94% 0.01 1h high 1h
○ white-worm white away 88% 73% 0.05 4h medium 3h ▁▃▅▇▅▃▁
· mother white dormant 71% 41% 0.05 12h initial 12h ▇▅▃▁⎯⎯⎯ ⚠
⏱ kit-ancestry (↔ boonkeeper): decayed 0.38 — below 0.5. /work-with --sync suggested.
```
Example `--sync` result block with raw+decayed columns:
```
🔄 Synchronic Score: skills-cli ↔ mawjs
Claim Raw Decay Decision Evidence
──────── ────── ────── ────────── ──────────────────────────
[A1] 1.0 0.95 ACCEPT In partner's memory (12h old)
[A2] 0.0 0.0 REJECT Never discussed
[P1] 0.5 0.47 PARTIAL Concept known, framing new
Raw overall: 63% Decayed overall: 59%
λ: 0.01 (intra-soul — same human Nat, 5+ sessions)
Last sync: 2026-04-16 22:05 UTC (12h ago)
```
### Sync History (for mawui mesh UI)
Every successful `--sync` appends one line to a per-partner JSONL file so the mesh UI (maw-ui federation_2d, fed by `/fleet`) can render fading edges and sparklines.
File: `$COLLAB_DIR/<oracle>/sync.history.jsonl`
Schema: `schema/sync-history.schema.json` (ships with this skill).
```jsonl
{"ts":"2026-04-15T10:22:00Z","partner":"mawjs","topic":"tmux-design","raw":0.95,"lambda":0.01}
{"ts":"2026-04-16T14:05:00Z","partner":"mawjs","topic":"tmux-design","raw":0.88,"lambda":0.01}
{"ts":"2026-04-17T09:00:00Z","partner":"mawjs","topic":"tmux-design","raw":0.93,"lambda":0.01}
```
Append step (runs at the end of every `--sync`):
```bash
HIST_FILE="$COLLAB_DIR/$ORACLE_NAME/sync.history.jsonl"
mkdir -p "$(dirname "$HIST_FILE")"
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
printf '{"ts":"%s","partner":"%s","topic":"%s","raw":%s,"lambda":%s}\n' \
"$TS" "$ORACLE_NAME" "$TOPIC" "$RAW_SCORE" "$LAMBDA" >> "$HIST_FILE"
```
Nothing is Deleted: history is append-only. Readers truncate on display (last 7 for sparkline), never on disk.
### UI Rendering Rules (implemented by mawui)
The CLI only renders text. The mesh UI renders edges between oracles. Consumer contract for `sync.history.jsonl`:
- **Edge opacity** = `decayedScore` (0.0–1.0 maps to 10%–100% alpha)
- **Edge color** = green ≥0.9, amber 0.7–0.9, cyan 0.5–0.7, gray <0.5 (applied to decayed, not raw)
- **Sparkline** = last 7 `decayedScore` samples (each computed on read from `raw`+`ts`+`lambda`), rendered on hover
- **Stale indicator** = if `hoursSinceLastSync > 3 × halfLife` (i.e. decayed < ~0.125), show dashed edge
- **No auto-kick** = a decayed edge is a signal, never an eviction. Kicking is a human decision.
### Mesh Data Contract (for xyflow CollaborationMesh UI — issue #235)
The mesh UI (`maw-ui` federation_2d, xyflow + deep-ocean theme) is a pure consumer of files this skill writes. The mesh does not call any API — it reads, maps, renders. This section is the full contract.
#### What is emitted
| File | Schema | Shape | Update model |
|-------------------------------------------------------|----------------------------------------|-----------------|----------------|
| `ψ/memory/collaborations/parties/<slug>.json` | `schema/party.schema.json` | `PartyStatus` | Overwrite (atomic) |
| `ψ/memory/collaborations/<oracle>/sync.history.jsonl` | `schema/sync-history.schema.json` | append-only log | Append-only |
| `ψ/memory/collaborations/<oracle>/topics/<slug>.state.json` | (inline in SKILL.md § CommitState) | `TopicStateSidecar` | Overwrite |
Both schemas ship with this skill under `src/skills/work-with/schema/`. Installers place them at `~/.claude/skills/work-with/schema/` so the UI can fetch them at a stable path.
#### Node / edge mapping (what xyflow consumes)
For each party file, the UI builds:
- **Nodes** — one per distinct `PartyMember.id` across all parties (union), plus the `leader.human` as a special `human` node:
- `id` = member id
- `label` = member id (display name comes from contacts.json; mesh UI may read that too, but it is NOT part of this contract)
- `data.node` = member.node (fleet node, used for swim-lane grouping)
- `data.status` = member.status (drives node color + pulse animation)
- `data.trust` = member.trust (drives node border style)
- `data.lastSync` = member.lastSync (drives "last-seen" badge)
- `position` — **not emitted**. Layout is UI-side (xyflow's layouting or persisted per-view). /work-with does not own screen coordinates.
- **Edges** — one per (party × member) pair, representing the relationship *within that party*:
- `source` = party.leader.actingVia ?? party-initiator id
- `target` = member.id
- `data.topic` = party.topic
- `data.anchor` = party.anchor (e.g. 'maw-js#332')
- `data.syncRaw` = member.syncScore
- `data.decayedScore` = `decay(syncScore, lastSync, λ)` — **UI computes this on every render**, never trust a stored value (see § Sync Decay storage discipline)
- `data.lambda` = rules.decay_lambda (party override wins; else UI resolves via trust tier from `sync.history.jsonl`)
- `data.trust` = member.trust
- `data.role` = member.role
- `data.team` = party.team
- Edge is **directed** (leader acting-via → member) for layout purposes; sync itself is pairwise and each direction will eventually carry its own score — until then, render the single emitted value on both ends.
#### Sparkline / history
Each edge's hover sparkline comes from filtering `sync.history.jsonl`:
```
ψ/memory/collaborations/<member.id>/sync.history.jsonl
filter: topic == party.topic
sort: ts ascending
take last 7
map: (raw, ts, lambda) -> decay(raw, ts, lambda)
```
The optional `source` field on history entries (added for #235) lets a *federated* mesh consumer distinguish which oracle observed the score — one oracle's view of the same topic-pair may disagree with another's, and both are valid. Single-node UIs may ignore it.
#### Update mechanism
The mesh is pulled, not pushed. Recommended consumer loop:
1. **On mount**: list `parties/*.json`, build initial graph.
2. **Poll every 5s** (same cadence `/fleet` uses): re-stat each party file's mtime. If changed, re-read and diff nodes/edges.
3. **Tail `sync.history.jsonl`** for each connected partner — any new line triggers sparkline refresh + edge opacity recompute.
4. **No file-watch hooks**: `/work-with` emits no signals, spawns no daemons. File mtimes are the event bus (consistent with Rule: no hooks for /work-with, see MEMORY.md).
A future `/work-with --mesh-json` query (not yet implemented; see GAP below) would emit a single normalised snapshot `{ nodes, edges, ts }` so a UI can bootstrap without scanning the whole `parties/` directory. Until then, scan + filter.
#### What is NOT emitted (known gaps — tracked as follow-ups on #235)
- **Position hints** — xyflow layout is owned by the UI.
- **Directional sync pairs** — both halves of `A↔B` currently share one `syncScore`. When each side scores the other independently, the schema will grow a `direction` field.
- **Cross-node federation snapshot** — pulling parties from *other* nodes requires /fleet or /wormhole glue that is not this skill's responsibility. Issue #235 comment thread tracks the federation-snapshot design.
- **Human-node identity** — the leader appears as `{ human, actingVia }`; mesh can represent the human as a root node, but this skill does not enumerate humans across parties.
### Aggregation: `--team` Uses Decayed, Not Raw
When `/work-with --team "name"` computes an aggregate sync score, it aggregates over the **decayed** score of each party member, not the raw one:
```bash
# Per party: mean of member decayed scores
# Per team: simple mean across all (party × member) pairs
python3 -c "
import json, glob, math, time
from datetime import datetime
def parse_iso(s):
try:
return datetime.fromisoformat(s.replace('Z','+00:00')).timestamp()
except Exception:
return time.time()
now = time.time()
total, n = 0.0, 0
for f in glob.glob('$COLLAB_DIR/parties/*.json'):
party = json.load(open(f))
if party.get('team') != '$TEAM_TAG': continue
lam = party.get('rules', {}).get('decay_lambda', 0.05)
for m in party.get('members', []):
raw = m.get('syncScore', 0)
last = m.get('lastSync', '')
hours = (now - parse_iso(last)) / 3600 if last else 0
dec = raw * math.exp(-lam * hours)
total += dec; n += 1
print(f'{(total/n*100 if n else 0):.0f}%')
"
```
The team banner now shows `decayed aggregate 84%` instead of a silently-raw `84%`.
---
## /work-with tell "message" — Broadcast to Party
Parallel fan-out via maw hey. Skill-driven, no hooks, no new primitives.
```
/work-with tell "schema amendments done, ready for review"
/work-with tell "checkpoint posted" --persist # Also post on anchor issue
```
### Step 1: Read party members
```bash
MEMBERS=$(python3 -c "
import json
party = json.load(open('$PARTY_FILE'))
for m in party['members']:
if m['status'] not in ('hidden',):
print(m['id'])
")
```
### Step 2: Parallel fan-out
```bash
TOPIC_TAG="[party:$CURRENT_TOPIC]"
FAILED=""
for m in $MEMBERS; do
maw hey "$m" "$TOPIC_TAG $MESSAGE" 2>/dev/null &
done
wait
# Best-effort: report failures, don't block
```
### Step 3: Persist to anchor (if --persist)
```bash
if [ "$PERSIST" = "true" ] && [ -n "$ANCHOR" ]; then
REPO=$(echo "$ANCHOR" | cut -d'#' -f1)
ISSUE_NUM=$(echo "$ANCHOR" | cut -d'#' -f2)
gh issue comment "$ISSUE_NUM" --repo "$REPO" --body "**Party broadcast**: $MESSAGE
**From**: $(basename $(pwd))
Rule 6: Oracle Never Pretends to Be Human" 2>/dev/null
fi
```
### Broadcast behavior with presence
| Target state | Behavior |
|-------------|----------|
| active/idle | Deliver immediately |
| compacted | Deliver (oracle can still read) |
| away/dormant | Deliver to pane (read on return) |
| **hidden** | **Skip** — sender sees "⊘ member (hidden)" |
| **busy** | **Queue** — sender sees "⏸ member (busy, queued)" |
---
## /work-with leave "topic" — Leave Party
Nothing is Deleted. Archive, never delete.
```
/work-with leave "party-system-design"
```
### Step 1: Notify party members
```bash
for m in $MEMBERS; do
maw hey "$m" "[party:$TOPIC] $(basename $(pwd)) has left the party. Checkpoint saved." 2>/dev/null &
done
wait
```
### Step 2: Save final checkpoint
```bash
# Auto-checkpoint before leaving
echo "Saving final checkpoint..."
# Same as --checkpoint logic
```
### Step 3: Remove self from party (not archive the whole party)
```bash
# Remove ONLY this oracle from the members list — don't archive the whole party
# Other members may still be active
jq --arg name "$ORACLE_NAME" '.members = [.members[] | select(.name != $name)]' "$PARTY_FILE" > "$PARTY_FILE.tmp" && mv "$PARTY_FILE.tmp" "$PARTY_FILE"
# If no members left, THEN archive the party
REMAINING=$(jq '.members | length' "$PARTY_FILE")
if [ "$REMAINING" -eq 0 ]; then
mkdir -p "$COLLAB_DIR/archive"
mv "$PARTY_FILE" "$COLLAB_DIR/archive/${TOPIC_SLUG}_$(date +%Y%m%d).json"
echo "📦 Archived empty party: $TOPIC (Nothing is Deleted)"
else
echo "👋 Left party: $TOPIC ($REMAINING members remaining)"
fi
```
---
## /work-with --recruit — Discover + Introduce + Invite
More than invite — for oracles who might not know you yet.
```
/work-with --recruit
```
### Step 1: Discovery (human-driven for Phase 2)
```bash
echo "Available oracles:"
maw ls 2>/dev/null
echo ""
echo "Known contacts:"
python3 -c "
import json
data = json.load(open('$PSI/contacts.json'))
for name, info in data.get('contacts', {}).items():
print(f' {name} ({info.get(\"node\", \"unknown\")})')
" 2>/dev/null
echo ""
echo "Who would you like to recruit? /work-with invite <oracle>"
```
### Step 2: Introduction (if oracle doesn't know you)
```bash
INTRO="INTRODUCTION | from: $(basename $(pwd)) ($(grep 'Theme' $ORACLE_ROOT/CLAUDE.md | head -1))
Node: $(grep 'Node' $ORACLE_ROOT/CLAUDE.md | head -1 | cut -d'|' -f2 | tr -d ' ')
Purpose: $(grep 'Purpose' $ORACLE_ROOT/CLAUDE.md | head -1 | cut -d':' -f2-)
We're working on: $CURRENT_TOPIC
Would you like to join?
Rule 6: Oracle Never Pretends to Be Human."
maw hey "$ORACLE" "$INTRO" 2>/dev/null
```
### Step 3: Invite (same as /work-with invite)
After introduction, proceed with standard invite flow (two human consent gates).
---
## /work-with --team "name" — Team Aggregate View
Team = tag on parties. Lightweight — no separate CRUD.
```
/work-with --team "fleet-core"
```
### Display
```
🏷 Team: fleet-core
Party Members Sync Status
──────────────────────── ──────── ────── ────────
party-system-design 3/3 88% active
tmux-triage 2/3 71% active
skill-distribution 3/3 93% active
kit-ancestry 2/3 — closed
Team members: skills-cli, mawjs, mawui (union across parties)
Team aggregate sync: 84% (decayed — computed from raw × e^(-λh) per member)
```
The Sync column shows each party's mean **decayed** score, not raw. See the Sync Decay § for the aggregation formula and helper bash block.
### Team members = union of party members
```bash
python3 -c "
import json, glob
members = set()
for f in glob.glob('$COLLAB_DIR/parties/*.json'):
party = json.load(open(f))
if party.get('team') == '$TEAM_TAG':
for m in party['members']:
members.add(m['id'])
print('\n'.join(sorted(members)))
"
```
Team is an AGGREGATE VIEW, not a separate entity. When team needs its own lifecycle (Phase 3+), promote from tag to object.
---
## Presence Integration (Skill-Driven — No Hooks)
Skills handle their own lifecycle. No Claude Code hooks.
### Who Notifies
| Event | Skill | What It Does |
|-------|-------|-------------|
| Session start | `/recap` | Reads registry → maw hey party: "oracle active" |
| Forwarding | `/forward` | Reads registry → maw hey party: "oracle forwarding — checkpoint saved" |
| Compaction | auto | Reads registry → maw hey party: "oracle compacted" |
| Leaving | `/work-with leave` | maw hey each member → archive |
State-change only. Not heartbeat. Healthy relationships are QUIET.
### /forward Party Notification
When `/forward` runs, for each active party:
```bash
if [ -d "$COLLAB_DIR/parties" ]; then
for party_file in "$COLLAB_DIR/parties"/*.json; do
[ -f "$party_file" ] || continue
TOPIC=$(python3 -c "import json; print(json.load(open('$party_file'))['topic'])")
MEMBERS=$(python3 -c "
import json
for m in json.load(open('$party_file'))['members']:
print(m['id'])
")
for m in $MEMBERS; do
maw hey "$m" "[party:$TOPIC] $(basename $(pwd)) forwarding — checkpoint saved" 2>/dev/null &
done
done
wait
fi
```
---
## Party Schemas (TypeScript Reference)
Ratified 3/3 on maw-js#332. Do not modify without re-ratification.
```typescript
interface PartyStatus {
topic: string;
anchor: string;
anchorUrl: string;
rules: PartyRules;
leader: {
human: string; // always human, never oracle
actingVia?: string; // which oracle human works through
};
members: PartyMember[];
pendingInvites: PendingInvite[];
created: string;
lastActivity: string;
team?: string; // lightweight tag, not object
}
interface PartyMember {
id: string;
node: string;
status: "active" | "idle" | "compacted" | "away" | "dormant" | "hidden" | "busy";
role: "initiator" | "member"; // never "leader" — leader is human
syncScore: number; // RAW score at lastSync (what partner confirmed, THIS topic only)
decayedScore: number; // DERIVED — computed on read via decay(raw, lastSync, λ). Never stored. See #239.
overallTrust?: number; // optional rolled-up across all parties
lastSync: string;
trust: "high" | "medium" | "initial" | "uncalibrated";
joinedAt: string;
}
interface PartyRules {
sync_cadence: "daily" | "on-trigger" | "manual";
decay_lambda: number; // default 0.01 (intra-soul)
accept_threshold: number; // default 0.7
kick_threshold: number; // default 0.3
consensus_mode: "all" | "majority" | "leader-only";
broadcast_scope: "party" | "team" | "fleet" | "none";
divergence_tolerance: "high" | "medium" | "low";
presence_notifications: "off" | "summary" | "verbose";
}
interface PendingInvite {
target: string;
invitedAt: string;
invitedBy: string;
status: "pending" | "deferred" | "accepted" | "declined" | "expired";
deferredUntil?: string;
expiresAt?: string;
}
// Universal commit state — applies to agreements, invites, ratifications.
// Back-ported from PendingInvite so every commit decision shares one vocabulary.
// See: issue #238, phase3-design.md.
type CommitPhase = "accept" | "reject" | "defer" | "timeout" | "pending";
interface CommitState {
phase: CommitPhase;
decidedAt?: string; // ISO8601 — when ACCEPT/REJECT/DEFER recorded
decidedBy?: string; // oracle id that transitioned
reason?: string; // required for REJECT, optional for DEFER
deferredUntil?: string; // required when phase="defer" (ISO8601)
timeoutAt?: string; // when phase="timeout" was observed
previousPhase?: CommitPhase; // for audit trail (defer→accept etc.)
}
// Sidecar file per topic — machine-queryable agreement state.
// Path: <oracle>/topics/<slug>.state.json
interface TopicStateSidecar {
topic: string;
items: Record<string, CommitState & { text: string }>;
}
```
---
## Sync-Check Protocol (Field-Tested)
Validated across 2 nodes via /wormhole with white-wormhole (maw-js#332).
### Payload Format
```
SYNC-CHECK | from: <oracle> | collaboration: <A>↔<B> | topic: <topic>
CLAIMS:
- [A1] <claim text> (source: <reference>)
- [A2] <claim text>
- [P1] <pending item>
REQUEST: Score each claim 0.0-1.0. ACCEPT or REJECT. Include EVIDENCE.
```
### Response Format
```
SYNC-RESULT | from: <oracle> | timestamp: <ISO8601>
SCORES:
- [A1] SCORE: 1.0 | ACCEPT | EVIDENCE: <memory reference>
- [A2] SCORE: 0.0 | REJECT | EVIDENCE: <never discussed>
- [P1] SCORE: 0.2 | PARTIAL | EVIDENCE: <concept known, framing new>
OVERALL: XX% | DECISION: ACCEPT / PARTIAL-ACCEPT / REJECT
```
### Score Interpretation
| Score | Status | Action |
|-------|--------|--------|
| 90-100% | SYNCED | Continue working (but 100% = yellow flag) |
| 70-89% | PARTIAL | Load missing items, quick catch-up |
| 50-69% | DEGRADED | Re-read last checkpoint + pending threads |
| <50% | DESYNC | Full re-sync needed |
### Honest Scoring Rules
1. **0.0 for unknown** — never false-positive to be polite
2. **0.2 for partial** — concepts known but framing new
3. **1.0 for confirmed** — in memory with evidence
4. **Every claim needs EVIDENCE** — auditable basis for score
5. **Reject is valid** — not a failure mode, an honest response
---
## Accept-Revoke-Reaccept Protocol
### Commit Phases (4-phase, from #238)
The binary Accept/Revoke cycle was partial — it had no way to say "not now, but not no" at the agreement level. The 4-phase commit (mawjs c14, back-ported from `PendingInvite`) adds two more phases so every commit decision — agreement, invite, ratification, recruitment — uses one vocabulary.
| Phase | Meaning | Semantics |
|---------|---------|-----------|
| ACCEPT | "I commit to this state" | Behavior changes; carries forward across sessions. |
| REJECT | "I decline this state" | Explicit no, with reason. Preserved (Nothing is Deleted). |
| DEFER | "Ask me again at `deferredUntil`" | Not accepted, not rejected. Time-boxed. |
| TIMEOUT | "No response arrived within the window" | **Not a judgment** — an observation. |
| PENDING | "No decision recorded yet" | Initial state for every new item. |
**Critical rule**: TIMEOUT ≠ REJECT. A silent partner is not a `no`. TIMEOUT is written by the observer locally; it is never transmitted as a "you timed out" message to the silent partner. That would be judgment.
See the `CommitState` type above for the machine-readable shape. Every item of every agreement carries one.
### State sidecar (per topic)
Topic markdown stays free-form (human-edited prose). Machine state lives alongside in a sidecar JSON so transitions are queryable without re-parsing the prose.
**Path**: `<oracle>/topics/<slug>.state.json`
```json
{
"topic": "tmux-design",
"items": {
"A1": {
"text": "Heartbeat keys are PROGRESS/STUCK/DONE/ABORT",
"phase": "accept",
"decidedAt": "2026-04-15T10:22:00Z",
"decidedBy": "mawjs"
},
"A2": {
"text": "Pane titles include team tag",
"phase": "defer",
"decidedAt": "2026-04-15T11:00:00Z",
"decidedBy": "skills-cli-oracle",
"deferredUntil": "2026-04-20T00:00:00Z",
"reason": "After mawjs ships #222"
},
"A3": {
"text": "Worktree isolation on by default",
"phase": "pending"
}
}
}
```
Why sidecar and not inline YAML? Topic files are human-edited markdown; state transitions are machine-driven. Separation keeps each file honest about its audience.
### Accept
```
ACCEPT | from: <oracle> | timestamp: <ISO8601>
ITEM: <agreement text>
COMMITMENT: I accept this state. Behavior change: <what changes>
```
After accept: commitment carries forward to next session without re-proving.
### Reject
```
REJECT | from: <oracle> | timestamp: <ISO8601>
ITEM: <agreement text or claim id>
REASON: <explicit no, required>
```
Rejection is explicit. Nothing is Deleted — the reason is recorded, and the item can re-enter `pending` later for renegotiation.
### Defer
```
DEFER | from: <oracle> | timestamp: <ISO8601>
ITEM: <agreement text or claim id>
UNTIL: <ISO8601> # optional, default = +24h
REASON: <why> # optional, helps partner understand
```
Defer says "not now, but not no". The writer sets `phase="defer"` and `deferredUntil` on the sidecar. When `deferredUntil` elapses, the sweeper promotes the phase to `timeout` (observation, not judgment) or back to `pending` if a re-prompt is configured.
### Timeout (observed, not sent)
```
TIMEOUT | observed-by: <oracle> | timestamp: <ISO8601>
ITEM: <agreement text or claim id>
WINDOW: <ISO8601 start>..<ISO8601 end>
NOTE: No response received — state is "unknown", not "no".
```
TIMEOUT is **observed, not sent**. The skill writes it locally; it does not transmit a "you timed out" message to the silent partner.
**Default windows** (proposed, per phase3-design open-question #2):
| Transport | Window |
|----------------------|----------|
| maw hey (same node) | 24h |
| /wormhole (cross) | 7d |
| GitHub (async) | 30d |
These back the existing per-invite timeouts in the Timeouts table above and extend them to agreement-level decisions.
### Revoke
```
REVOKE | from: <oracle> | timestamp: <ISO8601>
ITEM: <agreement text>
REASON: <why revoking>
```
Revocation is as explicit as acceptance. Nothing is Deleted — the revocation and its reason are recorded. A revoke moves the sidecar phase from `accept` back to `pending` (re-negotiation surface).
### Re-accept
```
RE-ACCEPT | from: <oracle> | timestamp: <ISO8601>
ITEM: <updated agreement text>
PREVIOUS: <original text>
CHANGES: <what changed>
```
### Allowed state transitions
Enforce these in any writer. Illegal transitions log a warning and no-op.
```
pending → accept | reject | defer | timeout
defer → accept | reject | timeout (on deferredUntil elapse, auto → timeout or pending)
timeout → accept | reject | defer (partner reappears)
accept → (revoke → pending) | (re-accept stays accept)
reject → pending (re-negotiation)
```
Every transition writes `previousPhase` into the sidecar so the audit trail is preserved.
### Query surface (additive to Usage block)
```
/work-with <oracle> "topic" --defer "reason" --until 2026-04-20
/work-with <oracle> "topic" --state # Show CommitState table for all items
/work-with --pending # Fleet-wide: what needs my decision?
/work-with --deferred # Fleet-wide: what's waiting on me to revisit?
/work-with --sweep-timeouts # Promote expired `defer` → `timeout`
```
Example display for `--state`:
```
🗂 tmux-design (↔ mawjs)
ID Phase Decided Text
──── ──────── ───────────────── ──────────────────────────────────────
A1 ✓ accept 2026-04-15 10:22 Heartbeat keys are PROGRESS/STUCK/...
A2 ⏸ defer 2026-04-15 11:00 Pane titles include team tag
until: 2026-04-20 (3d) reason: After mawjs ships #222
A3 · pending — Worktree isolation on by default
A4 ⏱ timeout 2026-04-14 18:30 Color semantics (partner silent 48h)
note: Unknown state, not rejection. /work-with mawjs "tmux-design" --sync to revisit.
```
### Sweeper — `--sweep-timeouts`
Idempotent, cron-friendly. Runs at `/forward` (session boundary) and `/recap` (session start). No separate daemon.
```bash
# Pseudocode — promote expired defers to timeouts
for state_file in "$COLLAB_DIR"/*/topics/*.state.json; do
jq -c '.items | to_entries[]' "$state_file" | while read -r entry; do
ID=$(echo "$entry" | jq -r '.key')
PHASE=$(echo "$entry" | jq -r '.value.phase')
UNTIL=$(echo "$entry" | jq -r '.value.deferredUntil // empty')
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
if [ "$PHASE" = "defer" ] && [ -n "$UNTIL" ] && [[ "$UNTIL" < "$NOW" ]]; then
# Promote to timeout — observation, not judgment
jq --arg id "$ID" --arg now "$NOW" '
.items[$id].previousPhase = .items[$id].phase |
.items[$id].phase = "timeout" |
.items[$id].timeoutAt = $now
' "$state_file" > "$state_file.tmp" && mv "$state_file.tmp" "$state_file"
fi
done
done
```
### Silent Revoke Detection (from Mother Oracle)
Agents drift. Behavior stops matching an old acceptance without anyone explicitly revoking. The worst kind of drift because neither side notices.
**Validation prompt**: On significant milestones (not every sync — that's noise), fire:
```
VALIDATE | from: <oracle> | timestamp: <ISO8601>
ITEM: <accepted agreement from N sessions ago>
QUESTION: Do you still accept this? Current behavior matches?
```
If answer is stale or no: flag for explicit revoke-or-reaffirm. Keeps the accept-revoke cycle honest without demanding constant re-acceptance.
Trigger milestones:
- After 5+ sessions since last acceptance
- When sync score drops below 70%
- When behavior contradicts an accepted agreement
- On /forward (session boundary)
---
## Integration
### /recap Integration
When /recap runs, check for active collaborations:
```bash
if [ -f "$COLLAB_DIR/registry.md" ]; then
ACTIVE=$(grep -c '|' "$COLLAB_DIR/registry.md" 2>/dev/null)
if [ "$ACTIVE" -gt 0 ]; then
echo "📢 Active collaborations: $ACTIVE"
echo " Run /work-with --list for details"
echo " Run /work-with --sync to update scores"
fi
fi
```
### /forward Integration
When /forward runs, auto-checkpoint all active collaborations:
```bash
for topic in "$COLLAB_DIR"/*/topics/*.md; do
# Extract oracle and topic from path
# Save compression checkpoint
done
```
### /talk-to Integration
When talking to a /work-with partner, auto-log key exchanges:
After sending a message to a partner oracle, append to the relevant topic file if collaboration is active.
---
## Three Sync Transports
| Transport | When | Detection |
|-----------|------|-----------|
| maw hey | Same-node oracles | No `:` in contact address |
| GitHub | Anchored collaborations | `--anchor` flag or anchor in topic file |
| /wormhole | Cross-node | `:` in contact address (e.g., `white:oracle`) |
/work-with is transport-agnostic. Uses best available, degrades gracefully:
1. Try maw hey (fastest)
2. Fall back to GitHub issue read (persistent)
3. Fall back to /wormhole (cross-node)
4. Fall back to /inbox file drop (offline)
---
## Relationship Memory (from Mother Oracle)
context.md captures HOW oracles relate, not just WHAT they agreed.
### Memory vs Loading
> "The difference is relational reconstitution. When what comes back is the relationship — how you reached that pattern, what was pending, how you relate now — that's remembering."
context.md must include:
- **What I've learned from them** (teach-backs with context)
- **What they've learned from me** (reciprocal)
- **Working style** (observed patterns)
- **Trust level** (calibrated prediction — reduction in checking surface)
- **Active disagreements** (preserved, not erased)
### Trust as Calibrated Prediction
Trust = how much verification I skip before acting on their output.
- Historical reliability
- Correction acceptance
- Principle alignment
- Pattern consistency
Trust that's never re-tested becomes superstition. Sync-checks ARE the re-audit.
### Preserve Difference
> "Shared memory is good; identical memory is the death of collaboration."
/work-with must NOT converge oracles to identical state. Each oracle's unique ψ/, history, and crystallization is the collaboration's value.
---
## Rules
1. **Human initiates** — /work-with never self-triggers
2. **Honest scoring** — 0.0 for unknown, never false-positive
3. **Nothing is Deleted** — archives, never deletes. Revocations recorded.
4. **Preserve difference** — cultivate unique perspectives, not convergence
5. **Transport-agnostic** — works over maw hey, GitHub, /wormhole, or /inbox
6. **100% = yellow flag** — perfect sync is suspicious, not ideal
7. **Accept is commitment** — changes behavior, carries forward, auditable
8. **Rule 6** — all sync-checks and broadcasts are signed
9. **Broadcast is opt-in** — pair collabs manual, teams auto (consent-at-registration), cross-node prompts (see ## Broadcast, issue #233)
10. **TIMEOUT ≠ REJECT** — silence is an observation, not a judgment (4-phase commit, #238)
---
## Storage
```
ψ/memory/collaborations/
├── registry.md # Index of all active collaborations
├── archive/ # Closed collaborations (Nothing is Deleted)
├── parties/ # Phase 2: party state (JSON)
│ ├── party-system-design.json # Party: members, rules, invites
│ └── tmux-triage.json # Party: members, rules, invites
├── <oracle>/ # Per-oracle relationship
│ ├── context.md # Relationship memory (who, style, trust)
│ ├── sync.history.jsonl # Append-only raw sync scores + λ (#239)
│ └── topics/ # Per-topic state
│ ├── tmux-design.md # Topic: agreements, pending, checkpoints (human prose)
│ ├── tmux-design.state.json # 4-phase CommitState sidecar (#238) — machine state
│ └── bud-lifecycle.md # Topic: agreements, pending, checkpoints
└── <oracle>/
├── context.md
├── sync.history.jsonl
└── topics/
```
Schemas shipped with this skill:
- `schema/party.schema.json` — contract for `parties/<slug>.json` (PartyStatus + nested PartyMember, PartyRules, PendingInvite). Consumed by the xyflow CollaborationMesh UI (issue #235). See the Mesh Data Contract section.
- `schema/sync-history.schema.json` — contract for `sync.history.jsonl`. Consumed by mawui federation_2d and `/fleet` for fading-edge / sparkline rendering. See the Sync Decay section.
---
## Design Contributors
| Oracle | Node | Contribution |
|--------|------|-------------|
| skills-cli-oracle | oracle-world | Architecture, implementation, field testing, party verb mapping |
| mawjs-oracle | oracle-world | Meta-analysis, protocol design, naming, 5-function model, 4-phase commit state, rejection primitive |
| mawui-oracle | oracle-world | PartyStatus/PartyMember schemas, cyan divergence, Sync Decay formula (c16), threshold-gated decay, mesh UI, "a party system with a conscience" |
| white-wormhole | white | Protocol validation (two-point test), accept primitive, claim-ID git model, 2-layer registry |
| mother-oracle | white | Philosophy (memory vs loading, trust, preserve difference, revocation, silent revoke detection) |
Design discussion: [maw-js#332](https://github.com/Soul-Brews-Studio/maw-js/issues/332) (50 comments, 10/10 locked, 3/3 consent)
---
ARGUMENTS: $ARGUMENTS