Canonical source: ROADMAP.md This page is generated for the docs site from the repository root document.
Shoal Roadmap¶
This roadmap outlines the planned development for Shoal as a fish-first, personal workflow tool that may still be useful to others.
Release history: See CHANGELOG.md for completed releases (v0.4.0–v0.29.0).
v0.15.0: FastMCP Integration¶
Priority: expose Shoal orchestration as MCP tools so agents can call Shoal natively.
Phase 1 — Shoal MCP server¶
- [x] Add
fastmcp>=3.0.0as optional dependency - [x] Create
mcp_shoal_server.pywith tools: list_sessions, send_keys, create_session, kill_session, session_status, session_info - [x] Register
shoal-orchestratorin default MCP server registry - [x] Template support for robo workflows
Phase 2 — Protocol-aware health checks¶
- [x] Replace manual JSON-RPC probe in
mcp doctorwith FastMCP Client - [x] Better error diagnostics from protocol-level failures
Phase 3 — Transport evaluation (spike)¶
- [x] Investigate FastMCP UDS transport support
- [x] Measure HTTP vs UDS performance for MCP traffic
- [x] Decide go/no-go for byte bridge replacement
- See docs/transport-spike.md for full findings
v0.16.0: Remote Sessions¶
Priority: monitor and control agents running on remote machines via SSH tunnel + HTTP client.
Phase 1 — Documentation + fish wrapper¶
- [x] Ship
shoal-remotefish function wrapping SSH - [x] Document remote usage patterns
Phase 2 — shoal remote subcommand group¶
- [x]
shoal remote connect/disconnect— SSH tunnel management - [x]
shoal remote status/ls— HTTP GET via tunnel, Rich-formatted - [x]
shoal remote send/attach— interact with remote sessions - [x] Remote host config in
~/.config/shoal/config.toml
Phase 3 — Status bar integration (deferred)¶
- [ ] Fish status bar polls remote WebSocket for session status
v0.17.0: Demo Overhaul, Diagnostics & Observability¶
Priority: onboarding experience, operational visibility, and developer ergonomics.
- [x] Demo & onboarding overhaul — split monolithic
demo.pyintocli/demo/package - [x]
shoal demo tutorial— interactive 7-step guided walkthrough - [x] Redesigned
shoal demo tour— 7 user-facing feature steps - [x]
shoal config showandshoal mcp registry— config introspection commands - [x]
shoal diag— diagnostics command (DB, watcher, tmux, MCP sockets) - [x] Logging infrastructure — named loggers for 8 modules, structured JSON output
- [x] Context propagation —
ContextVar-based session/request ID threading - [x] Request ID middleware —
X-Request-IDon all API requests - [x] Journal frontmatter — Obsidian-compatible YAML metadata on creation
- [x] Project-local templates —
.shoal/templates/search path in git root - [x] Structured session journals — append-only markdown with archive on kill
- [x] FastMCP HTTP transport default for
shoal-orchestrator - [x] Remote sessions —
shoal remotesubcommand group (7 commands via SSH tunnel) - [x] XDG Base Directory compliance across config/state/runtime paths
- [x]
extra="forbid"on config models;ConfigLoadErrorfor TOML parse errors
v0.18.0: Lifecycle Hooks, Observability & Robo Supervisor¶
Priority: event-driven architecture, agent observability, and autonomous supervision.
Phase 1 — Lifecycle Hooks (foundation)¶
- [x]
LifecycleEventenum:session_created,session_killed,session_forked,status_changed - [x] Async callback registry on lifecycle service (
lifecycle.on()/lifecycle.emit()) - [x] Fish event emission —
emit shoal_status_changed <name> <status>after Python hooks fire - [x] Built-in hooks: auto-journal entry on session create, status transition logging
- [x]
shoal setup fishinstalls example hook templates (__shoal_on_waiting, etc.) - [x] Fix
send_keysin MCP server to auto-append Enter for Claude Code tool profile - [x] Pre-commit hook bypass strategy for Shoal-spawned agent sessions
Phase 2 — Agent Observability¶
- [x]
capture_paneMCP tool + underlying Python function (read last N lines from a session's terminal) - [x]
status_transitionsSQLite table —(session_id, from_status, to_status, timestamp, pane_snapshot) - [x] Journal auto-entries for status changes (written via lifecycle hook)
- [x]
shoal history <session>CLI command — status timeline with durations - [x] New MCP tools:
capture_pane,read_history - [x] Server Composition Gateway investigation (FastMCP
mount()) — no-go, deferred to backlog. See docs/composition-gateway.md
Phase 3 — Session Graph¶
- [x]
parent_id,tags,template_namefields onSessionState - [x]
shoal tag <session> add/remove <tag>command - [x]
shoal ls --tag <tag>andshoal ls --tree(fork relationships) - [x]
shoal journal search <query>across all session journals - [x] Fork tracking:
fork_session_lifecyclerecordsparent_id
Phase 4 — Robo Supervision Loop¶
- [x]
services/robo_supervisor.py— async programmatic supervision loop - [x] Wire up
auto_approve,poll_interval,waiting_timeoutfrom robo config - [x] Pattern-based safe-to-approve detection (reads pane content, checks against patterns)
- [x] LLM escalation: ambiguous cases escalated to robo agent session via MCP tools
- [x] Robo journal: logs every decision (approved, escalated, timed out)
- [x]
shoal robo watch— start the supervision loop (foreground + background daemon mode)
Design Decisions¶
- Hook architecture: Code-level async callbacks (internal) + fish event emission (external). Python hooks handle infrastructure (journal, DB, robo). Fish events let users customize behavior without writing Python —
notify-send, ntfy webhooks, custom scripts via--on-event. - Status history: Both SQLite table (programmatic queries, robo decision-making) and journal entries (human-readable narrative). Written by a single lifecycle hook.
- Robo autonomy: Layered — deterministic Python loop handles simple cases (auto-approve known-safe prompts, timeout escalation). Ambiguous cases escalated to LLM agent session. Programmatic layer uses Python API directly; LLM layer uses MCP tools (each interface used where it's designed for).
- MCP interface principle: MCP is the agent interface, Python is the infrastructure interface. They share the same underlying functions. Programmatic code calls Python directly; LLM agents call MCP tools.
v0.19.0¶
Released 2026-03-07
--versionflag: Addedshoal --version/shoal versionCLI command- XDG directory naming: Renamed
state_dir()→data_dir()andruntime_dir()→state_dir()to match XDG spec; updated all callers - Archived journal lookup:
shoal journal <name>now searches archived sessions too; addedshoal history <name>command for status transition history - Branch naming: Extracted
infer_branch_name(),validate_branch_name(),ALLOWED_BRANCH_CATEGORIEStocore/git.py; fixed doublefeat/prefix bug
v0.20.0¶
Released 2026-03-07
- Template
setup_commands: Newsetup_commands: list[str]field onSessionTemplateConfigandTemplateMixinConfig; commands run viasend-keysbefore agent launch - Orphaned worktree detection:
wt cleanupnow detects orphaned worktrees in CWD even when no sessions exist for that repo in the DB - Agent readiness signals: Replace
asyncio.sleep(1)hack with poll-until-pattern readiness check; newasync_wait_for_ready()helper incore/tmux.py - Batch MCP operations:
send_keys,capture_pane,session_status,kill_sessionnow acceptsession: str | list[str]; batch input returns{"results": {name: data}}
v0.21.0¶
Released 2026-03-07
- PyPI publish: Package name
shoal-clion PyPI;pipx install shoal-cli/uv tool install shoal-clias primary install path - pyproject.toml metadata: Added
authors,keywords,classifiers(Development Status :: 4 - Beta), and[project.urls] - PyPI trusted publisher:
.github/workflows/release.ymlpublish job using OIDC viapypa/gh-action-pypi-publish - README badge/copy refresh: Version badge v0.21.0-beta, test count 1087, ecosystem note removed, status table updated through v0.21.0
- Docs copy fixes: CONTRIBUTING.md and ARCHITECTURE.md stack reference updated to Pi as primary; getting-started.md PyPI install as primary
v0.27.0¶
Released 2026-03-31
- Meta-repo workspace routing:
.shoal/workspace.tomlmanifest,--repoflag, auto-match by worktree hint or path prefix (SMORGASBORD §3.1) - Structured handoff packets (B2):
HandoffArtifactwith git context (diff stat, commit count),to_dict()JSON export, auto-generation on kill,shoal handoffcommand with--json/--save,shoal handoff-ls - Operating modes (B3): Data-driven
MODE_REGISTRYwithModeSpec, 3 new modes (planner, implementer, reviewer),shoal mode ls, auto-tagging from modes and templates - Template
tagsandmodefields: Union-merged during inheritance, auto-applied to sessions - Branch categories:
plan,impl,review,batchadded - Docs: New "Handoffs & Modes" mkdocs page, Bedrock section in AGENTS.md
v0.28.0¶
Released 2026-03-31
- Flagship fleet demo:
shoal demo fleetruns a 6-step scripted showcase — planner → implementer → reviewer → supervisor escalation → overnight progress → morning fleet summary - Shoal-native skills:
SkillConfigmodel,discover_skills()searches.shoal/skills/and~/.config/shoal/skills/,shoal skill lscommand, auto-symlink into.claude/skills/ - Project-level
.shoal.toml: Committed config at git root with[env],setup_commands,default_tool,default_template. Precedence: project < template < CLI flags - Cross-agent skill setup: OpenCode agents (
.opencode/agents/), omp skills (.omp/skills/), and rules for both tools claude-reviewtemplate: Review-oriented Claude session for reviewer mode- Docs: CLI reference updated with incident, handoff, mode, and skill commands
v0.29.0¶
Released 2026-03-31
- MCP tools for robo workflows:
mark_complete,read_worktree_file,list_worktree_files— MCP server now exposes 18 tools - PyApp binary distribution: Self-contained
shoalbinary via PyApp packaging. Homebrew formula atTheShoal/tap/shoal-cli - omp as default tool: Replaced
piwithomp(oh-my-pi) as the default tool across config, robo profiles, mode presets, and templates - Deferred CLI imports: All subcommand modules now use lazy imports via thin wrappers in
cli/__init__.py, improvingshoal --helpstartup latency - Config model split: Monolithic
models/config.pyrefactored into focused submodules (general.py,tools.py,templates.py,hooks.py,workspace.py,robo.py)
v0.30.0¶
Released 2026-04-01
- Claw runtime provider: Shoal now manages lobster-party Claw sessions via gRPC.
RuntimeKind.clawwith fullClawRuntimeProviderimplementing all 13 Protocol methods - MCP ↔ A2A bridge: 5 new
shoal-orchestratorMCP tools for cross-system agent collaboration:send_to_claw,claw_status,list_claws,claw_health,sync_claw_conversations - Conversation/journal sync:
core/claw_conversations.pyreads lobster-party QMD files.import_claw_turns()andexport_journal_to_qmd()enable bidirectional sync.shoal sync <session>CLI command - Lobster Party proto stubs: Generated protobuf/gRPC stubs in
src/shoal/core/proto/. Regenerate withjust gen-protos - Integration spec:
INTEGRATION.mddocuments the full Shoal × Lobster Party × Smorgasbord integration architecture
v0.31.4¶
Released 2026-04-01
- Fixed: Broken mermaid markup on docs homepage
Backlog¶
Done (kept for reference)¶
- ~~Structured handoff packets (B2)~~ — v0.27.0
- ~~Role/mode templates (B3)~~ — v0.27.0
- ~~Flagship secure-fleet demo (B6)~~ — v0.28.0 (
shoal demo fleet) - ~~Template
setup_commands~~ — v0.20.0 - ~~Project-level
.shoal.toml~~ — v0.28.0 - ~~Dashboard actions~~ — v0.22.0
- ~~Agent readiness signals~~ — v0.20.0
- ~~omp integration~~ — v0.29.0 (default tool, tool profile, templates)
- ~~Auto-commit on kill~~ — v0.22.0 (
general.auto_commit) - ~~Batch MCP commands~~ — v0.20.0 (
session: str | list[str]) - ~~Robo merge MCP tools~~ — v0.24.0 (
merge_branch,branch_status) - ~~Worker completion signals~~ — v0.24.0 (
shoal done) + v0.29.0 (mark_complete,read_worktree_file) - ~~Linux notifications~~ — solved by fish event hooks
- ~~Claw runtime + A2A bridge~~ — v0.30.0 (gRPC runtime provider, 5 new MCP tools, journal↔QMD sync)
Remaining¶
- ~~Dreamer LLM + session summary MCP~~:
ai_client.pywraps Bedrock/HTTP-gateway/stub;session_summaryMCP tool; summaries persisted to journal;shoal-status --extended. Shipped this session. - ~~FsWatcher + command failure events~~:
fs_watcher.py(watchfiles, now core dep);file_changed/command_failedlifecycle events;shoal proactive fs-watchCLI. Shipped this session. - ~~Agent Bus~~:
messages+failure_contextsSQLite tables;message_bus.py;send_session_message,receive_session_messages,mark_session_message_consumedMCP tools;shoal proactive messageCLI. Shipped this session. - ~~Proactive Supervisor (Scout)~~:
proactive_supervisor.pysubscribes tocommand_failed, stores failure context packets;get_failure_contextMCP tool withconsumeflag;ProactiveSupervisorConfiginRoboProfileConfig. Shipped this session. - Experimental Hermes-over-Shoal autonomy: Keep the local-only HTTP/MCP supervisor path in development — strict whitelist, read-first fleet digests, bounded team spawning, and retry reconciliation before broader rollout.
- Server Composition Gateway: Per-session MCP aggregation via FastMCP
mount()— investigated, no-go for now (spike findings). Revisit when FastMCP adds UDS transport or robo needs unified cross-session MCP. - ~~
branch_prefixenforcement inshoal new~~ — shipped v0.37.0 (infer_branch_name+[template.git]wired throughsession_create.pyand MCP server). - direnv/mise integration (deferred): Opt-in
env_managerfield on templates. Explicit opt-in only, never auto-detect. - ~~Pre-commit hook profile (low priority):
[template.git]extension —.pre-commit-config.yamlpath symlinked into worktree. Shipped v0.37.2.
Handoff¶
This section is maintained by Claude Code sessions. Each session records what was accomplished and what should happen next, so the next session (which may start with a fresh context) can pick up seamlessly.
Session: 2026-04-02 — [template.git] per-session git practices¶
What we did:
- Added
TemplateGitConfigmodel (user_name,user_email,commit_template,branch_prefix) tomodels/config/templates.py; exported frommodels.config _parse_template_dataandload_mixinnow extract[template.git]/[mixin.git]subsections_merge_templates: git inherits from parent; child[template.git]replaces whole (same asworktree)_apply_mixin: field-level merge — non-empty mixin fields win without blanking unset template fields- New
_apply_template_git_config_asynchelper: emitsgit config --localcommands +GIT_AUTHOR_*/GIT_COMMITTER_*env vars; called from bothcreate_session_lifecycleandfork_session_lifecycle(step 3.4) examples/config/templates/base-dev.toml: added commented[template.git]reference block- New
examples/config/templates/mixins/git-identity.tomlshowing standalone mixin usage - 13 new tests in
tests/test_template_git_config.py; CI: 1441+ passed, 4 skipped
Current state:
- Branch:
main, commitb5b7dbbpushed [template.git]is fully optional; no-op when all fields emptybranch_prefixis a convention hint only — not yet enforced duringshoal newbranch naming (future work)
What to do next:
- Live Claw gRPC validation: Connect to production Claw endpoint, run
get_agent_card()/send_message()smoke test (unblocked,shoal[claw]extra in place) - ~~
branch_prefixenforcement inshoal new~~:infer_branch_namegains optionalbranch_prefixparam;_add_implextractstemplate_cfg.git.branch_prefixand threads it through. Shipped this session. - Pre-commit hook profile (low priority):
[template.git]extension — specify a.pre-commit-config.yamlpath to symlink into the worktree
Session: 2026-04-02 — Fins polish, MCP server restart¶
What we did:
- Fixed
shoal-mcp-serverstartup:fastmcpis in the[mcp]optional extra — reinstalledshoal-cli[mcp]viauv tool installso the tool venv has it - Killed stale
shoal-mcp-serverstdio processes; restarted HTTP instance on port 8390 - Struck through
--sync-claw default from configin backlog (already shipped previous session) - Fins polish (
refactor(fins): formalize contract version policy, consolidate registry helpers): SUPPORTED_CONTRACT_VERSIONS: frozenset[int] = frozenset({1})infin_runtime.py; error message now cites the supported set- Removed dead
_registry_url,_download_fin,FinSource.resolve()frommodels/fin.py install_fin()callsfin_repo.resolve_fin()instead ofsource.resolve()- Trimmed 10 duplicate tests from
test_fin_install_remote.py(all covered bytest_services_fin_repo.py) - CI: 1510 passed, 4 skipped (−10 removed duplicate tests)
Current state:
- Branch:
main, commit1ce1a00pushed SUPPORTED_CONTRACT_VERSIONSis the single place to extend when a v2 contract spec ships- MCP orchestrator server requires a session restart to reconnect (stale client connection)
What to do next:
- Per-session git practices:
[template.git]section with commit conventions, branch naming, and per-session identity vars (GIT_AUTHOR_NAME,GIT_COMMITTER_EMAIL) - Connect to a production Claw endpoint and run
get_agent_card()/send_message()for real traffic validation (live Claw gRPC smoke test — unblocked)
Session: 2026-04-02 — Claw MCP modernization + remote status bar¶
What we did:
- Modernized Claw MCP tools in
mcp_shoal_server.py: keyword-argClawClient, dict returns,GRPC_AVAILABLEguard unified,send_to_clawdeprecated as wrapper forsend_a2a_message_tool - Fixed
sync_claw_conversations_toolfallback: checkscfg.claw.conversations_dirfirst, then~/conversations - Rewrote
tests/test_mcp_claw_tools.py(25/25 pass); fixedtests/test_a2a_grpc_roundtrip.pycollection guard (class nested underif _grpc_for_test:) - Removed 3 stale
# type: ignore[attr-defined]comments inlobster_a2a.py - Added flow architecture view to dashboard (
/flowroute,flow_context(),flow.htmltemplate, CSS fonts) - Shipped
shoal-status --remote <name>:generate_remote_status()hitsGET /statuson configured remote API host; 9 new tests intest_status_bar.py - CI: 1520 passed, 4 skipped (all 3 features clean through
just fmt-check lint typecheck test)
Current state:
- Branch:
main, all commits pushed (3 new commits sincev0.34.0) shoal-status --remote <name>requires[remote.<name>]inconfig.tomlwithhostandapi_port(default 8080)- Remote status bar backlog item marked done
What to do next:
- Connect to a production Claw endpoint and run
get_agent_card()/send_message()for real traffic validation (live Claw gRPC smoke test — unblocked) - Fins polish: registry/remote install semantics, subprocess timeout controls, contract version support window policy
- Per-session git practices:
[template.git]section with commit conventions, branch naming, and per-session identity vars
Session: 2026-04-02 — conversations_dir config default + gRPC round-trip tests¶
What we did:
- Added
conversations_dir: Path | NonetoClawConfig— maps to[claw] conversations_dirinconfig.toml shoal handoff <session>now falls back toconfig.claw.conversations_dirwhen--sync-clawis absent; explicit flag still takes priority- Added 2 new tests:
test_handoff_show_without_sync_clawpatched to mock config;test_handoff_show_sync_claw_from_configasserts config fallback runs sync - Wrote
tests/test_a2a_grpc_roundtrip.py: 5 in-process gRPC tests usinggrpc.aio.server()+_TestAgentLoopServicer; skipped in standard CI, run withuv run --extra claw pytest - Validated full round-trip: GetAgentCard → AgentCard Pydantic model; SendMessage echo; ListTasks empty; channel reuse; explicit task_id preservation
- Fixed descriptor pool load order in test file:
# noqa: I001on first try-block import preservesa2a_core_pb2beforea2a_claw_pb2_grpc - CI: 1516 passed, 2 skipped (6 new tests vs prior 1510)
Current state:
- Branch:
main, taggedv0.34.0(dashboard release); pending push to remote for prior session ClawConfig.conversations_dirdefaults to None; set inconfig.tomlto enable auto-sync without flag- gRPC round-trip tests: 5/5 pass under
uv run --extra claw pytest tests/test_a2a_grpc_roundtrip.py
What to do next:
git push origin main && git push origin v0.34.0to publish the v0.34.0 release- Connect to a production Claw endpoint and run
get_agent_card()/send_message()for real traffic validation -
Remote status bar: Fish status bar polling remote WebSocket (
/wson main API) for session status — backlog item -
Pick up any of the three newly formalized backlog items above
Session: 2026-04-02 — Pisces integration (shoal-first + lobster-party)¶
What we did:
- Added
examples/config/tools/pisces.toml— tool profile for the pisces fork of oh-my-pi;status_provider = "omp_compat"(pisces shares omp's TUI);socket_env = "PISCES_MCP_SOCKETS"wires shoal's MCP pool into pisces sessions - Added
examples/config/templates/pisces-dev.toml— thin stub extendingbase-dev, pinstool = "pisces"(same pattern asomp-dev.toml) - Added
examples/config/robo/pisces.toml— robo supervisor profile using pisces as the agent tool - Fixed
status_provider.py:"pisces"and"omp"now both map to"omp_compat"provider; previously"pisces"incorrectly mapped to"pi" - Implemented
socket_envinjection inlifecycle.py: - New
_mcp_socket_env_injection(provisioned, tool)— readstool.mcp.socket_env, returns{env_var: "sock1:sock2:..."}when set - New
_inject_mcp_socket_env_async(sock_env, tmux_session, session_id)— sets tmux environment + sendsset -gxto running shell - Wired into
create_session_lifecycleandfork_session_lifecycleafter MCP provisioning; claw sessions skipped (remote gRPC, no tmux)
Current state:
socket_envfield was previously declared inToolConfig.mcpbut never consumed; now fully wired end-to-endpisces.tomltool profile ships alongsideomp.toml,opencode.toml,pi.toml- pisces binary (in the pisces repo) was rebuilt; symlink at
~/.local/bin/piscesis current
What to do next:
- End-to-end smoke test:
shoal new --template pisces-dev, confirmPISCES_MCP_SOCKETSis set in the session environment when MCP servers are configured - P0.5 (lobster-party): update
grpc.rsto invokepiscesinstead ofopencode, parse pisces event schema — unblocked once lobster-party repo is accessible - Live Claw gRPC validation (pre-existing next step):
get_agent_card()+send_message()smoke test against production endpoint
Session: 2026-04-02 — Proactive agent assistance (Dreamer LLM, FsWatcher, Agent Bus, Scout)¶
What we did:
src/shoal/services/ai_client.py: async LLM wrapper supporting Bedrock (boto3), HTTP AI Gateway, stub fallback. Readscfg.dreamer.ai(provider,endpoint).DreamerAIConfig+DreamerConfig.aiinmodels/config/general.py; default model changed toamazon.nova-lite-v1:0.dreamer.py: summaries persisted to journal viaappend_entry(..., source="dreamer").session_summaryMCP tool: reads in-process Dreamer singleton first, falls back to journal entries withsource=="dreamer".shoal-status --extended: emitsdreamer_summariesdict keyed by session name.watchfilespromoted to core dependency (removedproactiveoptional extra).src/shoal/services/fs_watcher.py: async FsWatcher backed bywatchfiles.awatch; emitsfile_changedlifecycle events per session worktree. Global singleton viainit_fs_watcher()/get_fs_watcher().LifecycleEvent.file_changed+LifecycleEvent.command_failedadded tomodels/state.py.Watcher._poll_cycle: emitscommand_failedon error status transition, passingpane_snapshotandold_status.shoal proactive fs-watch start/status+shoal proactive message send/listCLI commands (src/shoal/cli/proactive.py).messages+failure_contextstables in SQLite schema;ShoalDBgains 8 new methods.src/shoal/core/message_bus.py: thin wrappers over newShoalDBmethods.send_session_message,receive_session_messages,mark_session_message_consumedMCP tools.src/shoal/services/proactive_supervisor.py: subscribes tocommand_failedvialifecycle.on(); stores failure context packets; serves them viaget_failure_contextMCP tool (withconsumeflag).ProactiveSupervisorConfigembedded inRoboProfileConfig.- Tour updated to 31 MCP tools. CI: 1529 passed, 4 skipped.
Current state:
- Branch:
main, commit6dbbffe(unpushed) - 31 MCP tools in
shoal-orchestrator proactive_supervisor.pywires into lifecycle events viaregister_proactive_hook(); caller must invoke this during startup (not yet wired intolifecycle.pybootstrap — intentional, avoids unconditional DB access at import time)ProactiveConfigonShoalConfigandProactiveSupervisorConfigonRoboProfileConfigare opt-in; no runtime effect unless supervisor is initialised
What to do next:
- Wire
register_proactive_hookinto startup: call fromservices/lifecycle.pybootstrap whencfg.proactive.enabledis True (requires passingcfgto the lifecycle module or using lazy init) - Wire
init_fs_watcherinto lifecycle startup: similar pattern — start watching session worktrees when a session is created, stop on kill - ~~Live Claw gRPC validation~~ — renamed Lobster; validation remains pending (requires live endpoint)
- ~~
branch_prefixenforcement~~ — shipped v0.37.0
Session: 2026-04-03 — QMD memory, Agent Bus enrichment, Lobster rename, v0.37.0¶
What we did:
src/shoal/core/qmd.py: dual-plane conversation memory — Markdown full-text + JSON sidecar (schema_version, structured metadata);SyncResult,ImportResultdataclasses; backward-compatible readerssrc/shoal/core/conversation_index.py:ConversationIndexfor fast handoff retrieval; indexed by week bucketsrc/shoal/core/conversations.py/lobster_conversations.py: QMD import/export surface;cast()for type-safe DB dict accesssrc/shoal/core/journal.py+handoff.py: structured handoff packets pull from conversation index- SOUL.md auto-load: fin env and MCP context both receive SOUL content at startup
- Claw scheduler subsystem:
claw_scheduler.py— SQLite-backed, fair round-robin, dead-letter queue - Agent Bus enrichment: typed message envelopes (
kind,correlation_id,priority,requires_ack);watch_session_messages,get_workflow_messages,watch_session_actionsMCP tools - Action/approval lifecycle:
request_session_action,list_pending_session_actions,approve/deny_session_actionMCP tools - Full claw→lobster rename:
LobsterClient,LobsterRuntimeState,LobsterA2AClient,LobsterConfig,shoal[lobster]extra; all user-visible strings updated - Simplification pass:
get_running_loop(),asyncio.to_thread()for blocking QMD calls,ConfigDict(extra="forbid")onClawTask - mypy --strict clean across all 128 source files;
cast(int/float, ...)for object-typed dict values just cigreen: 1673 tests, 1669 passed, 4 skipped- Docs pass:
lobster-quickref.mdrewritten,lobster-integration.mdstale refs fixed,cli-reference.mdgainsshoal lobstersection, nav adds Features Overview + Fleet Doctrine + Flows Design - Tagged and pushed
v0.37.0
Current state:
- Branch:
main, tagv0.37.0, pushed toorigin/main - Working tree: clean
- 47 MCP tools total in
shoal-orchestrator proactive_supervisor.pyandinit_fs_watcherwired into lifecycle bootstrap via_init_proactive_hooks()(called fromregister_builtin_hooks(), gated oncfg.proactive.enabled; avoids unconditional DB access at import time).
What to do next:
- ~~Wire
register_proactive_hook+init_fs_watcherinto lifecycle bootstrap~~: shipped v0.37.1 (_init_proactive_hooks()gated oncfg.proactive.enabled) - Live Lobster gRPC validation: smoke test
get_agent_card()+send_message()against a real Lobster orchestrator (requires endpoint access) - ~~Pre-commit hook profile~~: shipped v0.37.2 (
[template.git].pre_commit_configsymlinks.pre-commit-config.yamlinto worktree)
Session: 2026-04-03 (v2) — Bug fixes, FsWatcher/ProactiveSupervisor tests, pre-commit hook profile¶
What we did:
-
command_failedhook bug fixed (services/proactive_supervisor.py):_handle_command_failed(**kwargs)was missing the leadingeventpositional argument.lifecycle.emit()calls hooks ascb(event, **kwargs), so everycommand_failedevent raisedTypeError(silently caught by emit's guard). The Scout proactive supervisor was effectively dead since v0.36.x. Fixed to(event: LifecycleEvent, **kwargs: object). Tagged and shipped v0.37.1. -
Tests for
FsWatcher(tests/test_fs_watcher.py): 20 tests covering singleton, path add/remove/replace, start/stop idempotency,_should_ignore,_WatchFilter,_dispatch_changes(emit wiring viashoal.services.lifecycle.emit, ignore filter, error isolation). -
Tests for
ProactiveSupervisor(tests/test_proactive_supervisor.py): 18 tests:on_command_failed,get/consume_failure_context, TTL expiry dispatch, singleton lifecycle,register_proactive_hookwiring,_init_proactive_hooksenabled/disabled/idempotent (patch targets at source modules, notshoal.services.lifecycle.*since functions are locally imported). Fix patch paths:shoal.core.config.load_config,shoal.services.fs_watcher.get_fs_watcher,shoal.services.proactive_supervisor.get_proactive_supervisor,shoal.services.proactive_supervisor.init_proactive_supervisor,shoal.services.lifecycle.emit. Total CI: 1728 passed, 4 skipped. -
Pre-commit hook profile (
models/config/templates.py,services/lifecycle.py): New[template.git].pre_commit_configfield. At session creation time,<work_dir>/.pre-commit-config.yaml -> <src>symlink is created sopre-commitpicks it up automatically. Silently no-ops if source is absent._symlink_pre_commit_confighelper: idempotent (replaces existing symlink), expanduser() on source, exists() guard; all filesystem ops viaasyncio.to_thread(). Early-exit guard updated to includepre_commit_config. 7 new tests; examples inbase-dev.tomlandgit-identity.tomlmixin. Tagged and shipped v0.37.2.
Current state:
- Branch:
main, tagv0.37.2, pushed toorigin/main - Working tree: clean
- 1728 tests, 4 skipped
What to do next:
- Live Lobster gRPC validation: smoke test
get_agent_card()+send_message()against a real Lobster orchestrator (requires endpoint access)