Commit Graph

194 Commits

Author SHA1 Message Date
Levi Neely bb29ec6de7 Extract Assist to anvillm-acme, move logging to pkg/ 2026-03-20 15:29:06 +01:00
Levi Neely ed43407383 Move sandbox to pkg/ for external import 2026-03-20 15:18:50 +01:00
Levi Neely 8e50b84707 Extract beads to standalone 9beads service
- 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).
2026-03-20 15:13:02 +01:00
Levi Neely daf50d9783 beads: natural sort for hierarchical IDs
Sort bd-1.2 before bd-1.10 instead of lexicographic order.
2026-03-20 14:28:19 +01:00
Levi Neely 304bf25bf1 resolve prjdir from worktree/workspace dir 2026-03-18 23:07:45 +01:00
Levi Neely cfd4cf5daa mailbox: delete only removes from inbox, not completed 2026-03-18 17:20:41 +01:00
Levi Neely e78d91cf55 mailbox: add DeleteFromInbox, delete tries inbox then completed 2026-03-18 17:19:40 +01:00
Levi Neely b03324baaf beads: add deferred filter endpoint
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
2026-03-18 17:02:32 +01:00
Levi Neely 1f7d3ace54 fix crash on double mount 2026-03-18 09:25:28 +01:00
Levi Neely d3e2a543cb Update remaining read_inbox references to check_inbox 2026-03-18 08:20:41 +01:00
Levi Neely 3ab11f1c88 beads: remove workspace detection — can't distinguish from worktree-based 2026-03-16 15:11:27 +01:00
Levi Neely 6645cd9efb beads: fix worktree detection — allow worktree-based repos, reject feature workspaces 2026-03-16 15:08:51 +01:00
Levi Neely ff58ef9438 beads: move worktree/workspace validation to server-side 2026-03-16 15:04:13 +01:00
Levi Neely d5b30ed38e config: add shared ANVILLM_PROJECT_DIRS config
- Loaded once at startup, defaults to ~/src:~/prj
- Beads mount validation uses shared config
- Available for other uses via config.ProjectDirs
2026-03-16 14:52:28 +01:00
Levi Neely 7935950e4d beads: warn on overlapping mount paths 2026-03-16 14:47:39 +01:00
Levi Neely 69829a98a1 beads: add scope-based filtering for worktree/workspace isolation
- 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
2026-03-16 14:41:54 +01:00
Levi Neely 2d908c6dcd Assist: add Comment tag to leave comments on beads
- 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'
2026-03-16 11:23:46 +01:00
Levi Neely 47a97e5cea supervisor: replace Go package with anvillm-supervisor shell script
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>
2026-03-15 14:47:56 +01:00
Levi Neely 8e88660f65 supervisor: nudge idle worker-role bots to run their polling loop
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>
2026-03-15 14:25:21 +01:00
Levi Neely b4e84f57ee supervisor: stop sending inbox messages to bots
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>
2026-03-15 14:16:03 +01:00
Levi Neely 173746ce3b beads: add per-mount write mutex to serialize concurrent writes
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>
2026-03-15 13:57:07 +01:00
Levi Neely 9120e51215 beads,roles: emit BeadClaimed event; add bead loop to worker roles
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>
2026-03-14 20:58:58 +01:00
Levi Neely b52f0b5e85 beads: simplify claim — open only, orphan recovery via unclaim
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>
2026-03-14 20:51:22 +01:00
Levi Neely d0acd32f8f beads: atomic conditional claim with orphan takeover
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>
2026-03-14 20:48:14 +01:00
Levi Neely c58f0615a9 events: rename agent→source, embed full bead in BeadReady
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>
2026-03-14 20:36:38 +01:00
Levi Neely cb97b3640c p9: remove pending_approval/pending_review from protocol
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>
2026-03-14 20:13:17 +01:00
Levi Neely 62319aef68 supervisor: fix panic crash and add recover
- 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>
2026-03-14 16:08:54 +01:00
Levi Neely 9c5f98218c supervisor: exclude in_progress beads from assignment candidates
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>
2026-03-14 15:58:51 +01:00
Levi Neely 21450ba02c supervisor: remove redundant in-memory assignment tracking
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>
2026-03-14 15:55:18 +01:00
Levi Neely 68cc9445a9 supervisor: replace polling with event-driven work assignment
- 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>
2026-03-14 15:52:18 +01:00
Levi Neely d39a7f118d supervisor: align to new workflow
- 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>
2026-03-14 15:46:01 +01:00
Levi Neely 5436a4223d beads: restore update_bead.sh; block atomic fields from direct update
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>
2026-03-14 13:16:36 +01:00
Levi Neely e55742d691 beads: add atomic ctl operations; replace update_bead.sh
Add to 9p ctl handler: open, defer [until <RFC3339>], reopen, relate,
unrelate, config. Add corresponding mcptools scripts. Remove
update_bead.sh in favour of atomic operation scripts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 13:14:39 +01:00
Levi Neely 5dbd4cf777 beads: default new bead status to deferred
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>
2026-03-14 13:07:59 +01:00
Levi Neely 179a59bf16 p9: buffer Twrite chunks, dispatch on Tclunk
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>
2026-03-13 23:17:57 +01:00
Levi Neely 2a1d620a31 rename 9P endpoint from 'agent' to 'anvillm'
- Update socket path, MountService calls, path prefixes
- Update mcptools, scripts, docs, diagrams, services
- Fix idleSince initialization at session creation
2026-03-12 12:13:40 +01:00
Levi Neely 46da046fb3 tmux: remove FIFO plumbing, fix per-window metadata
- 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)
2026-03-12 11:47:37 +01:00
Levi Neely 39b49e83ce beads: reduce context overflow, simplify filters, atomic blockers
- 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
2026-03-11 09:45:20 +01:00
Levi Neely 919335a271 conductor: adaptive delegation based on available staff
- 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
2026-03-07 17:24:40 +01:00
Levi Neely 10d25a371a session: reset initialPromptSent when context is set
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>
2026-03-07 12:30:21 +01:00
Levi Neely e4ea258c6a session: remove wakeup channel, use ticker-only mail processing
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>
2026-03-06 22:38:21 +01:00
Levi Neely 7891d062ab p9: on role write, validate role exists and deliver to bot inbox
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>
2026-03-06 19:39:21 +01:00
Levi Neely 29f7b45adc session: wake mail processor immediately on inbox delivery or idle transition
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>
2026-03-06 19:35:41 +01:00
Levi Neely 15bf980298 p9/skills: flatten to <name>.md, add load_skill.sh, fix discover_skill.sh
Replace intent-based hierarchy (skills/<intent>/<name>/) with flat
skills/<name>.md files serving SKILL.md content directly. Update
discover_skill.sh to search the flat layout. Add load_skill.sh mcp
tool. Update anvillm-communication SKILL.md to use pipe syntax.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 19:04:58 +01:00
Levi Neely ebc162ac4f crash recovery: reset initialPromptSent and send inbox message
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
2026-03-06 17:27:50 +01:00
Levi Neely b913fcc644 Fix elevated bash execution 2026-03-06 17:02:57 +01:00
Levi Neely fc6cca01a8 Remove Go language support from execute_code (go run lacks stdin)
Keep code extensible for future language support.
2026-03-06 14:15:51 +01:00
Levi Neely 9643a9a034 Flatten tools 9P, restore SKILLS_PROMPT, remove role/tool discovery
- 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
2026-03-06 13:43:57 +01:00
Levi Neely 57cd96fc6c supervisor: require claimable label for bead assignment 2026-03-06 10:21:24 +01:00
Levi Neely b21c56b960 anvilmcp: use layered sandbox config from sandbox package
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.
2026-03-06 10:18:31 +01:00