- Remove embedded BeadsFS from anvilsrv
- Remove beads.go and related tests from p9 package
- Update Assist to connect to separate 'beads' 9P service
- Update mcptools scripts: anvillm/beads/* -> beads/*
Beads now served by 9beads (separate repo/process).
Add /beads/deferred aggregate endpoint and per-mount /beads/<mount>/deferred
endpoint to list beads with status=deferred.
- internal/p9/beads.go: add readDeferredFromStore and readDeferredAggregate
- internal/p9/server.go: wire up deferred in walk, directory listings
- cmd/Assist: update listBeadsWithFilter to use deferred endpoint
- Beads tagged with scope:<value> label, auto-derived from cwd
- Strict scope matching: bots only see beads matching their scope
- Updated scripts: create_bead, list_beads, list_ready_beads, wait_for_bead, search_beads, batch_create_beads, jira_to_beads, github_to_beads
- Fixed batch-create to handle raw JSON and create beads one at a time
- Added scope to JSON output and BeadReady events
- Add Comment tag to bead view window tagline
- New /AnviLLM/Tasks/{bead-id}/comment window with Put handler
- Fix comments display: JSON field is 'text' not 'body'
Remove the internal/supervisor Go package and cron-driven orphan check
script. Replace with a single anvillm-supervisor script invoked by cron
that handles both orphan bead recovery (--orphans, every 5m) and idle
worker nudging (--nudge, every 1m). Nudges use send_message.sh as user,
consistent with existing mail processing. anvilsrv no longer runs any
supervisor goroutine.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace dead assignWork() stub with nudgeIdleWorkers(), which sends a
prompt to any session whose role has worker: true in its front-matter
and has been idle for more than 15 seconds. A 15-second ticker drives
the checks. Bots that should be polling for beads will self-correct
after a brief idle period.
Add Worker bool to RoleMeta, parsed from "worker: true" front-matter,
and IsWorker() helper on RolesFS. Remove unused beads/mailbox/eventbus
deps from the supervisor.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BeadReady events are already fired when a bead becomes ready; bots
listen for those directly. Sending inbox messages was redundant and
caused duplicate/unexpected prompts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Concurrent writes to the same mount (e.g. two bots claiming the same
bead simultaneously) could race through RunInTransaction before either
committed. A per-mount writeMu serializes all writes without blocking
independent mounts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BeadClaimed fires on successful claim with source=beads/<mount> and
data={bead_id, assignee, mount}.
Worker roles (developer, devops, pkgmgr, researcher, tester, author)
now have a Bead Loop section: wait_for_bead.sh → claim → work →
complete → repeat. Reviewer role is spawned by workers, not looping.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claim now rejects anything not in status=open. Dead-assignee takeover
is handled by unclaiming the bead (which fires BeadReady), letting any
waiting bot claim it normally. Removes isAlive/SetSessionLiveness.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
claim now runs in a transaction: reads current status/assignee, allows
claim only if status=open or (status=in_progress and assignee is dead).
Returns ErrAlreadyClaimed if the current assignee is alive.
BeadsFS.SetSessionLiveness wires a func(agentID string) bool from the
session manager so the claim handler can check liveness without importing
the session package.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Event.Agent renamed to Event.Source (json: "source") — more accurate since
the field carries a session ID for session events and a subsystem identifier
for infrastructure events.
BeadReady source is now "beads/<mount>" so listeners can filter by mount
without fetching. BeadReady data is now the full bead JSON including comments,
eliminating the round trip a listener would need to decide whether to claim.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop status constants, readPendingFromStore, pending-approval/pending-review/resume
ctl handlers, and the pending virtual file from the 9P directory listing.
No migration needed — status is a string field; unused values simply won't appear.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- bead["id"].(string) was an unsafe type assertion — panicked if id was
missing or not a string, killing the server process. Use comma-ok form.
- Add recover() to Run() to log panics instead of crashing anvilsrv.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GetReadyWork returns both open and in_progress by default. Only open
unassigned beads should be offered to idle sessions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
s.assigned and s.lastAssigned were redundant: the bead's own assignee
field is the source of truth, and on server restart all sessions die
anyway making in_progress beads orphans for the cron to recover.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add EventBeadReady to eventbus, published by BeadsFS on open/reopen/unclaim
- Wire eventbus into BeadsFS via SetEventBus (called after server init)
- Supervisor now reacts to EventStateChange{idle} and EventBeadReady
instead of a 5s ticker; 60s fallback ticker retained for safety
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove "claimable" label requirement: ready beads (open, unblocked,
unassigned) are claimable by definition; deferred is now the default
new-bead state so no label gate is needed
- Fix mount name: use bead["mount"] from readReadyAggregate() instead
of filepath.Base(cwd) which was wrong after dropping friendly names
- Remove auto-mount on session state change: mounts are now explicit
(user/operator controlled via mount_beads.sh)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The update ctl command now rejects fields managed by atomic operations
(status, assignee, closed_at, close_reason, defer_until) with a hint
pointing to the correct command. update_bead.sh is restored with valid
fields documented in the header.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New beads created via the 9p interface now start as deferred instead
of open. Planning/human review is required to promote a bead to open
before the scheduler can assign it to a worker.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 9P client splits writes larger than msize into multiple Twrite
messages with increasing offsets. The server was dispatching each
Twrite immediately, so only the first chunk was ever processed —
causing JSON parse failures for payloads exceeding msize.
Fix: accumulate all Twrite data into a per-fid writeBuf, then dispatch
the fully-assembled payload in Tclunk. Tclunk can return Rerror if
dispatch fails, preserving error reporting to the caller.
This unblocks large bead descriptions/comments and message bodies
without any msize negotiation changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove dead streaming code: reader(), waitForReady(), StartupHandler, pipe-pane
- Switch recovery metadata from session-scoped set-environment to window-scoped set-option -w @key
- Sessions now start in idle state immediately (no startup wait)
- list_beads.sh/list_ready_beads.sh: filter to id,priority,title,status
- Add read_bead_comments.sh tool and Comments view in Assist
- Simplify Assist filters to All/Ready (was 6 status filters)
- Server-side filtering: list excludes closed at DB, ready uses GetReadyWork
- Default limit 100, DB-level filtering
- Atomic blockers= support in new command
- roles/conductor.md: discover roster before planning; adapt workflow
to available roles (dev-only, dev+review, dev+review+test, etc.);
drive iterative cycles; parallelize across multiple same-role bots;
report skipped phases instead of blocking on missing roles
- team-templates/debug: new workflow with conductor+developer+tester;
blocks until all roles are idle before returning
- list format: replace model field with role (field 5) in agent/list;
update Assist, anvillm, anvilwebgw, list_sessions.sh accordingly
- Assist /AnviLLM/: replace Model column with Role in session list
If context is written after the first mail nudge has already fired,
initialPromptSent was already true and the context would never be
injected. Resetting it on SetContext ensures the context is always
prepended to the next prompt regardless of timing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The wakeup channel caused duplicate message delivery: inbox delivery
and idle state transitions both signaled an immediate wakeup with
bypassIdleCheck=true, prompting bots before they were ready.
Replace with a simple 5-second ticker. The idle threshold is always
applied, eliminating the race condition. Worst-case delivery latency
is 10 seconds (one tick to drain outboxes, next tick to prompt).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of silently setting context on the session, writing to
agent/{id}/role now: validates the role exists in RolesFS (returning
"role not found" on failure), sets the role name on the session, and
delivers the role definition as a PROMPT_REQUEST from "user" to the
bot's inbox. The wakeup mechanism fires immediately via the onRecv
callback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add wakeupCh (buffered 1) to session.Manager. The mail processing loop
now selects on both the 5s ticker and the wakeup channel. Two events
signal the wakeup: a message delivered to any bot inbox (via onRecv
callback), and a session transitioning to idle with pending messages
(via OnStateChange). When woken, processMailboxes bypasses the
idleDuration threshold check. This covers all delivery paths including
direct DeliverToInbox calls from the supervisor.
Also flatten p9/roles to match p9/skills: remove focus-area directory
layer, expose roles as a flat <name>.md listing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On crash restart:
- Reset initialPromptSent flag so context gets re-injected
- Send 'Continue working.' inbox message from user to session
- Add OnCrashRestart callback to Session struct
- Flatten agent/tools/ to serve tools directly (no capability subdirs)
- Restore SKILLS_PROMPT.md with proactive skill discovery
- Remove discover_role.sh and discover_tool.sh
- Remove help endpoint from roles and tools
- Update all SKILL.md files to use flat tool paths
- Clear agent prompt in anvillm-agent.json
Reuse the same layered config approach as anvilsrv:
- global.yaml provides base permissions (including /usr, /lib, /bin)
- sandbox/<name>.yaml adds sandbox-specific permissions
- Merge uses most-permissive-wins strategy
This fixes the fallback to default sandbox, which now has proper
system paths from global.yaml.