Skip to content

feat(capability): LLM parser + TUI Ecosystem live tables + how-to docs (Phase 4.4) - #8

Merged
flg77 merged 1 commit into
mainfrom
feat/phase-4.4-ecosystem-tui-and-parser
Apr 29, 2026
Merged

feat(capability): LLM parser + TUI Ecosystem live tables + how-to docs (Phase 4.4)#8
flg77 merged 1 commit into
mainfrom
feat/phase-4.4-ecosystem-tui-and-parser

Conversation

@flg77

@flg77 flg77 commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Summary

Closes the Phase 4 ladder. After this PR:

  • The LLM can request capability invocations by emitting `[SKILL: id {json}]` / `[MCP: server.tool {json}]` markers in its response — the agent's task loop parses them, dispatches each through `CognitiveCore.invoke_skill` / `invoke_mcp_tool` (so Cat-A A-017/A-018 fire), and folds the outcomes into `TASK_COMPLETE`.
  • The TUI Ecosystem screen replaces its two roadmap placeholders with live DataTables of every loaded skill + MCP server, sourced from the same registries the agent uses.
  • Operators have two step-by-step how-to docs explaining how to add either kind of capability and what governance hooks fire.

What's in the box

`acc/capability_dispatch.py` (new)

Function Role
`parse_invocations(text)` Strict regex extraction of every marker. Order-preserving across `[SKILL:...]` and `[MCP:...]`. Single-line per marker, JSON args validated via stdlib `json`. Malformed args captured as `args_error` (not raised) so one bad marker doesn't drop neighbours.
`dispatch_invocations(invs, core, role)` Runs each parsed marker through `CognitiveCore.invoke_skill` / `invoke_mcp_tool`. Every exception path funnels into `InvocationOutcome.error` — one bad marker never raises out of the dispatcher.

`acc/agent.py`

`_handle_task` now parses + dispatches after `process_task` returns (no-op when the task was blocked or output is empty), and folds the `(kind, target, ok, error)` tuples into the new `invocations` field of the `TASK_COMPLETE` payload. Full result dicts remain in the LanceDB episode (reachable by `episode_id`); the bus payload carries summary metadata only.

`acc/cognitive_core.py`

`build_system_prompt` now documents the marker grammar inside the "Available skills" / "Available MCP servers" blocks added in PR 4.3, so the LLM knows the exact shape the dispatcher will recognise.

`acc/tui/screens/ecosystem.py`

Two roadmap `Static` placeholders replaced with live DataTables:

Table Columns
SKILLS Skill / Version / Risk / Requires
MCP SERVERS Server / Transport / Risk / Tools

Risk cells carry Rich colour markup (LOW=green, MEDIUM=yellow, HIGH=red, CRITICAL=bold red), matching the Compliance screen. Empty registries render a "no skills loaded — see howto-skills.md" guidance row instead of a blank table. Lazy imports keep the TUI startup time unchanged when `acc.skills` / `acc.mcp` are absent (e.g. in the minimal CLI image).

`docs/howto-skills.md` + `docs/howto-mcp.md` (new)

Six-step walkthroughs covering: directory layout → manifest → adapter (skills only) → role wiring → TUI verification → LLM marker invocation. Each includes the marker grammar, A-017 / A-018 enforcement detail, CRITICAL oversight semantics, and troubleshooting matrices.

Marker grammar

```
[SKILL: <skill_id> {}]
[SKILL: <skill_id>] # args default to {}

[MCP: <server_id>.<tool_name> {}]
[MCP: <server_id>.<tool_name>] # args default to {}
```

Single-line per marker. Tool names allow dots so nested namespacing (`fs.read`) is preserved. Malformed JSON is logged + skipped, not raised.

Smoke tests (all green locally)

  • `parse_invocations` extracts 3 mixed (skill + MCP) markers in source order.
  • Bad JSON: captured as `args_error`, not raised; marker not dispatched.
  • `dispatch_invocations` happy path returns the adapter dict.
  • `dispatch_invocations` denied path: A-017 block surfaces as `InvocationOutcome(ok=False, error='SkillForbiddenError: A-017 blocked ...')`.
  • `build_system_prompt` includes the marker grammar examples.
  • `EcosystemScreen` + helpers import cleanly; `_risk_cell` renders correct Rich markup for every level.

Existing suite: 139 unit tests (config + role-store + guardrails + compliance, with the lighthouse-OpenSSL-impaired `TestEd25519Validation` class deselected) pass unchanged.

Test plan

  • `from acc.capability_dispatch import parse_invocations, dispatch_invocations` imports cleanly.
  • `pytest tests/test_config.py tests/test_role_store.py tests/test_guardrails.py tests/test_compliance.py --deselect tests/test_role_store.py::TestEd25519Validation --no-cov -q` → 139 passed.
  • Boot the TUI on a coding_agent collective and navigate to Ecosystem — confirm SKILLS table shows `echo` and MCP SERVERS table shows `echo_server`, both with green LOW risk cells.
  • Walk through `docs/howto-skills.md` end-to-end — add a trivial `word_count` skill, confirm it appears in the table after agent restart.

Phase 4 delivery summary

PR Subject
4.1 Skills foundation (#? merged)
4.2 MCP foundation (#6 merged)
4.3 Role config + Cat-A A-017/A-018 (#7 merged)
4.4 LLM parser + TUI live tables + docs (this PR)

After this lands, the cell can synthesise organelles in-house (Skills) and admit symbiotic bacteria (MCP servers), the membrane enforces both via Cat-A, and the operator can see both surfaces live from the TUI.

…how-to docs (Phase 4.4)

Closes the Phase 4 ladder: roles can now ACTUALLY invoke skills + MCP
tools through governed entry points, the TUI surfaces every loaded
capability live, and operators have step-by-step docs for adding
either kind.

acc/capability_dispatch.py (new)
  parse_invocations(text)     — strict regex extraction of every
    [SKILL: <id> {<json>}] and [MCP: <server>.<tool> {<json>}] marker
    in LLM output.  Order-preserving (skills + MCPs interleave by
    source position), single-line per marker, JSON args validated
    via stdlib json.  Malformed args captured as args_error rather
    than raised so one bad marker doesn't drop neighbours.

  dispatch_invocations(invs, core, role) — runs each parsed marker
    through CognitiveCore.invoke_skill / invoke_mcp_tool (so Cat-A
    A-017/A-018 fire before the adapter executes).  Every exception
    path funnels into InvocationOutcome.error so the agent task loop
    has one shape to render in TUI / audit logs; one bad marker
    never raises out of the dispatcher.

acc/agent.py
  _handle_task: after process_task returns, parse the output for
  capability markers, dispatch them, fold the (kind, target, ok,
  error) tuples into the TASK_COMPLETE payload's new "invocations"
  field.  Full result dicts stay in the LanceDB episode (reachable
  by episode_id) — the bus payload only carries summary metadata.
  No-op when result.blocked or result.output empty.

acc/cognitive_core.py
  build_system_prompt: the "Available skills" / "Available MCP
  servers" blocks added in PR 4.3 now also document the
  [SKILL:...] / [MCP:...] marker grammar so the LLM knows the
  exact shape capability_dispatch will recognise.

acc/tui/screens/ecosystem.py
  Replaces the two roadmap Static placeholders with live DataTables:
    SKILLS table:      Skill | Version | Risk | Requires
    MCP SERVERS table: Server | Transport | Risk | Tools
  Both populated at mount via SkillRegistry / MCPRegistry .load_from()
  with $ACC_SKILLS_ROOT / $ACC_MCPS_ROOT discovery.  Risk-level cells
  carry colour markup (LOW=green / MEDIUM=yellow / HIGH=red /
  CRITICAL=bold red), matching the Compliance screen palette.
  Empty registries render a "no skills loaded — see howto-skills.md"
  guidance row instead of a blank table.  Lazy imports keep TUI
  startup unchanged when acc.skills / acc.mcp are absent (e.g. in
  the minimal CLI image).

docs/howto-skills.md (new)
  Six-step walkthrough: directory layout → manifest → adapter → role
  wiring → TUI verification → LLM marker invocation.  Documents the
  full marker grammar, A-017 enforcement points, CRITICAL oversight
  semantics, and a troubleshooting table covering the five most
  likely failure modes.

docs/howto-mcp.md (new)
  Sister doc covering MCP server integration: prerequisites → manifest
  → role wiring → TUI verification → LLM marker invocation.  Field
  cheatsheet for every mcp.yaml entry, A-018 enforcement detail,
  troubleshooting matrix, and a "when NOT to use an MCP server" note
  that points readers back to howto-skills.md when the capability
  could be a Skill instead.

Smoke tests (run locally — all green):
  * parse_invocations: extracts 3 markers (mixed skill + MCP) in source
    order, returns ParsedInvocation list with parsed args.
  * Bad JSON: captured as args_error, not raised; marker not dispatched.
  * dispatch happy path: returns adapter dict via invoke_skill.
  * dispatch denied path: A-017 block surfaces as InvocationOutcome
    with ok=False, error="SkillForbiddenError: A-017 blocked ...".
  * build_system_prompt: marker grammar examples now appear in the
    Available skills / Available MCP servers blocks.
  * EcosystemScreen + helpers import cleanly; _risk_cell renders the
    expected Rich markup for every level.

Existing test suite: 139 unit tests (config + role-store +
guardrails + compliance, with the lighthouse-OpenSSL-impaired Ed25519
class deselected) pass unchanged.

Phase 4 delivery complete.
@flg77
flg77 merged commit 7b72f3a into main Apr 29, 2026
@flg77
flg77 deleted the feat/phase-4.4-ecosystem-tui-and-parser branch April 29, 2026 20:58
flg77 added a commit that referenced this pull request May 20, 2026
Bumps that resolve the open Dependabot alerts on the repo:

- uv.lock: urllib3 2.6.3 -> 2.7.0   (#10 decompression-bomb High,
                                     #11 cross-origin sensitive headers High)
- uv.lock: idna     3.13  -> 3.15   (#13 idna.encode bypass — supersedes
                                     Dependabot PR #92)
- uv.lock: pytest   8.4.2 -> 9.0.3  (#9  tmpdir-handling CVE; the patched
                                     line is pytest 9.x, so pytest-asyncio
                                     bumps to 1.3.0 and pytest-cov to 7.1.0)
- pyproject.toml: pytest>=9.0,<10 + pytest-asyncio>=1.0,<2.0 widened to
  let the resolver onto the patched line.
- webgui/package.json: vite ^5.4.0 -> ^5.4.21 (#12 .map path traversal).

#8 (transformers Trainer-class arbitrary-code execution) cannot be
bumped today — the patched line is transformers 5.x but no
sentence-transformers release supports transformers 5 yet. We do NOT
use Trainer (only the SentenceTransformer encode() API for embeddings),
so the vulnerable code is not in our execution path. The sentence-
transformers range is widened to `<5.0` so the bump becomes a one-line
uv-lock change once ST releases support. Documented in pyproject.toml;
GitHub alert #8 to be dismissed with "vulnerable code not in execution
path".

42 webgui tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flg77 added a commit that referenced this pull request May 31, 2026
…3.42) (#8)

Closes followup #37 IN CODE (not just a proposal).

OpenSpec `20260531-orchestrator-repurpose-skills-mcp-specialist` Phase 1
ships the read-only catalog + NATS request/reply query subject.  Phases
2–7 deferred behind operator-review gates (recommendation markers, gap
analyser, [ROUTE:...] deprecation, marketplace mirror, dreamer M9 ride,
final removal).

Phase 1 is **purely additive**: existing routing paths
(orchestrator's [ROUTE:role:reason] AND Assistant's [PROPOSE_ROUTE]) both
keep working unchanged.  Future phases retire the legacy marker.

What landed:

1. `acc/capability_index.py` — `CapabilityIndex` class.  Scans
   `roles/*/role.yaml` + `mcps/*/mcp.yaml` + (optional) SkillRegistry at
   boot; deterministic query path with kind/name/domain/task_type/limit
   filters; revision counter increments on rebuild; SIGHUP-reload on
   non-Windows.  Pydantic v2 models with `extra="forbid"` reject
   malformed wire requests.  Empty roots are non-fatal (slim-edge
   deploys).

2. `acc/signals.py` — `subject_capability_query(cid)` +
   `subject_capability_recommend(cid)` (the recommend subject is
   declared in Phase 1 so consumers can subscribe early; no producer
   emits until Phase 2).

3. `acc/agent.py` — two coupled hooks:
   * `_maybe_build_capability_index()` — boot-time, role-gated, builds
     the index when `self.config.agent.role == "orchestrator"`; logs
     `capability_index: built at boot revision=1`.
   * `_handle_capability_query` (inside `_task_loop`) — NATS
     request/reply handler; unpacks msgpack, validates via Pydantic,
     queries index, publishes reply on `msg.reply` inbox.

4. `roles/orchestrator/role.yaml` — bumped to `v3.0.0-beta1`.  Purpose
   rewritten (Skills & MCP specialist).  New allowed_actions:
   `capability_query`, `capability_reply`.  Phase 1 RETAINS
   `can_route: true` for backward compat; Phase 4 deprecates with
   warning + auto-translate; Phase 3 flips it to false once the gap
   analyser ships.  Seed_context narrative explains the repurpose.

5. `tests/test_capability_index.py` — 16 tests covering scan
   correctness, query filters, Pydantic strictness, revision counter,
   optional SkillRegistry integration, empty-roots edge case, and the
   140-char summary truncation.

Tests:
- `pytest tests/test_capability_index.py` — 16 passed.
- `pytest -k "orchestrator or capability or role_def or signals"` —
  175 passed, 3 skipped, 0 failed.
- Full sweep `pytest tests/ --ignore=tests/container -x` —
  **2435 passed, 38 skipped, 0 failed**.

Downstream proposals unblocked (when their phases land):
- Sub-collective editor Phase 5 — "Suggest skills/MCPs" button queries
  capability.query.
- Dreamer Phase 6 — M9 distilled-skill ingest writes back to the
  catalog.
- Role-package format Phase 5 — marketplace mirror surfaces here.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
flg77 added a commit that referenced this pull request May 31, 2026
…wiring (2026-05-31)

New OpenSpec proposal `20260531-assistant-action-loop`. Triggered by
live lighthouse trace 2026-05-31 18:51-18:56 where the Assistant
under AUTO mode (small llama-3.2-3B-FP8 model, v0.3.41 stack):
  - Hallucinated non-existent role names (worker-pool, prompt) because
    seed_context describes ACC concepts abstractly but doesn't list
    what's actually available.
  - Asked "which roles do you want to run?" while a coding_agent was
    already running in the baseline roster.
  - Reasoned correctly ("I will execute Option A, spawning the
    agentset") but never emitted a [PROPOSE_SPAWN:...] marker.

Single architectural cause: the cognitive_core has no Observe step.
Every downstream primitive exists (CapabilityIndex shipped v0.3.42 PR
#8, AoA-P2b proposal queue v0.3.27, mode-aware dispatcher AoA-P2a
v0.3.26, sub-collective registry AoA-P3a v0.3.29) — but no wiring
connects them to the LLM call.

Proposal lands in 5 phases:
  1. Perception snapshot + system-prompt injection (READY).
  2. Hybrid dual-format marker emission (reasoning + JSON action).
  3. AUTO contract enforcement (extractor → escalation).
  4. Push-based roster snapshot.
  5. Reflexion-style reasoning-vs-action reconciliation + SIP reward.

Phase 1 is purely additive: new acc/perception.py + new
subject_roster_snapshot + system-prompt `## Currently available`
block + marker dispatch validation against snapshot roster (rejects
hallucinated target_role).

Brainstorm + open questions captured in
Notes/.../ACC-Assistant-Action-Loop/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
flg77 added a commit that referenced this pull request May 31, 2026
…ion + marker validation (v0.3.43) (#9)

OpenSpec `20260531-assistant-action-loop` Phase 1.

Today's lighthouse trace (2026-05-31 18:51-18:56, llama-3.2-3B under
AUTO mode) showed the Assistant gatekeeper:
  - Hallucinating `worker-pool` and `prompt` role names (neither exists).
  - Asking "which roles do you want to run?" while coding_agent was
    already running in the baseline roster.
  - Reasoning correctly ("I will execute Option A, spawning the
    agentset") but never emitting a [PROPOSE_SPAWN:...] marker.

Single architectural cause: cognitive_core had no Observe step.
Every downstream primitive existed (CapabilityIndex v0.3.42 PR #8,
AoA-P2b proposal queue v0.3.27, mode-aware dispatcher v0.3.26, sub-
collective registry v0.3.29) — but no wiring connected them to the
LLM call.

Phase 1 adds the Observe step.  Purely additive: non-Assistant roles
see zero behaviour change.

What landed (+685 / -7):

1. acc/perception.py — new module.  `PerceptionSnapshot` Pydantic
   model with stale flags per source; `snapshot_for_assistant`
   parallel-fans-out capability_query + roster_snapshot under a
   100ms budget; filesystem fallback when orchestrator is
   unreachable; `validate_marker_target` rejects hallucinated
   target roles; `render_currently_available_block` emits a token-
   conscious `## Currently available` block with running agents +
   available roles + MCPs + sub-collectives + a closing
   "roles not in this list do not exist" directive.

2. acc/signals.py — `subject_roster_snapshot(cid)`.  Phase 1 RPC
   shape; Phase 4 will swap to push-broadcast.

3. acc/agent.py — two coupled wirings:
   * arbiter `_subscribe_worker_reconcile` gains a
     `_handle_roster_snapshot` reply handler that serves the live
     heartbeat-tracked roster grouped by role.
   * cognitive_core construction sets `core._bus =
     self.backends.signaling` (both code paths) so the perception
     module has a NATS handle.

4. acc/cognitive_core.py — three coupled changes:
   * `_perception` + `_bus` attributes initialised on __init__.
   * `_process_task_body` gains an Observe step BEFORE
     build_system_prompt: when `role_label == "assistant"` AND bus
     is set, call `snapshot_for_assistant`; assign to `self._perception`.
   * `build_system_prompt` renders `## Currently available` block
     from `_perception` if present (same composable pattern as
     AoA-P3b's sub-collective block).
   * Marker dispatch validates `target_role` against the snapshot;
     hallucinated roles (`worker-pool`) are dropped with a WARNING
     log line BEFORE they reach AoA-P2b dispatch.

5. roles/assistant/role.yaml — bumped to v2.2.0.  seed_context
   gains an explicit "READ THE ## Currently available BLOCK BELOW
   FIRST" preamble + marker syntax reference + the AUTO-contract
   reminder ("Explaining without emitting a marker is an AUTO-
   contract violation").

6. tests/test_perception_snapshot.py — 13 new tests:
   * Snapshot happy path (bus + roster reply merge).
   * Stale capability path (timeout → fallback to filesystem).
   * No-bus path (early boot / tests).
   * Sub-collectives pass-through.
   * `validate_marker_target` — accepts roster + catalog roles;
     REJECTS the lighthouse trace's `worker-pool` / `prompt`
     hallucinations.
   * `render_currently_available_block` — running-agents-first
     ordering; no duplication of running roles in "Available roles";
     stale annotation; sub-collectives with DELEGATE marker hint;
     25-role cap with "and N more"; grounding directive at close.

Tests:
- pytest tests/test_perception_snapshot.py — 13 passed.
- pytest -k "cognitive or perception or assistant or marker or
  proposal or roster or arbiter" — 181 passed, 3 skipped.
- Full sweep `pytest tests/ --ignore=tests/container -x` —
  **2449 passed, 38 skipped, 0 failed** (+14 vs v0.3.42).

What this changes about today's trace:

Same operator prompt + same small model under AUTO would now produce:
- LLM sees `## Currently available` block listing assistant-1,
  arbiter, coding-1 (real running agents) + the 47 real roles in
  the catalog.
- LLM's "use the worker-pool role" suggestion goes away (no such
  role in the block + closing directive forbids inventing).
- IF the LLM emits `[PROPOSE_SPAWN:worker-pool:...]`, the marker
  dispatch's snapshot validation drops it with a WARNING.
- IF the LLM emits `[PROPOSE_SPAWN:coding_agent:...]` for a role
  in the catalog, AoA-P2b queues it (ASK_PERMISSIONS default) or
  dispatches it (AUTO).

Marker emission reliability on small models is Phase 2 (dual-
format reasoning + JSON action).  AUTO-contract enforcement when
no marker emitted is Phase 3.  Both deferred per proposal.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
flg77 added a commit that referenced this pull request Aug 23, 2026
…acks

The ACC Assistant now knows the @acc/supply-chain-roles pack and the guardrails
it must honor and surface when infusing/using it — so packaging work stays
governed end-to-end.

seed_context additions:
- list @acc/supply-chain-roles (packaging_engineer — RPM/DEB hardened, signed,
  attested builds) among the canonical first-party packs
- a general "rules of engagement — governance-sensitive packs" rule: before
  PROPOSE_INFUSE of such a pack, read its manifest rules of engagement
  (catalog_query / acc-pkg inspect) and state them back to the operator. The
  supply-chain pack is the reference case: builds in STAGING and only RECOMMENDS
  promotion (promotion to trusted/prod is CRITICAL, human-in-the-loop, never
  autonomous); signing keys referenced never placed in the workspace; hardening
  fail-closed; unjustified HIGH/CRITICAL CVE HOLDs the package. Propose the
  infuse + staging build, but route the promote decision to the operator.

Pack is live in the ecosystem catalog (acc-ecosystem v1.4.0, signed keypair +
keyless-OIDC); HowTo handed to acc-web (PR #55). Role source PR #7, tiers PR #8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant