Skip to content

feat(agent-card): self-declared persisted agent card, exposed on /tabs - #43

Open
a-biskoazh wants to merge 3 commits into
mainfrom
feat/api-agent-card
Open

feat(agent-card): self-declared persisted agent card, exposed on /tabs#43
a-biskoazh wants to merge 3 commits into
mainfrom
feat/api-agent-card

Conversation

@a-biskoazh

Copy link
Copy Markdown
Contributor

What

Re-homes the mx "agent card" onto modular-main and threads it end to end. The
eleven persisted, hook-immune per-tab fields — assignment, specialty,
orchestrator, objective, current_task (bounded permalog), rounds_active,
evaluations (bounded ring), usage_count, conventions, parent_tab_id,
rehome_status — plus the RoundsActive / Eval{Tokens,Scores} / Evaluation
types, are now writable (HTTP + CLI), persisted, restored across restarts,
applied to the live runtime tab, and exposed on /tabs.

Commit 432bcc0 (fields + types on TabState) is unchanged; this PR adds the
threading on top (commit 1ad37b5).

Layers touched

Layer Change
lib.rs append_current_task / append_evaluation / bump_usage / parse_conventions (+ *_MAX bounds)
api.rs CardChange enum, card_route_verb, is_rehome_state; SnapshotTab +11, TabInfo +11 (camelCase currentTaskLog/roundsActive/usageCount, snake for the rest); 4 owner-drain queues + inits; route arms (master-token only, like /context)
api/cards.rs (new) assignment / parent / rehome / card_verb / evaluation / bump_usage setters
headless.rs card fields on HeadlessTab; restore from TabState; persist back (the ..default() would otherwise wipe them); snapshot builder; drain of the 4 queues onto the runtime tab
app.rs (GUI parity) same: struct fields, from_state restore, both persist builders, snapshot builder, drain
api/tabs.rs populate the card fields on /tabs (currentTaskLog = current_task)
cli/* set-assignment, set-rehome-status + 8 card verbs (set-specialty/-orchestrator/-objective/-current-task/-rounds-active/-conventions/-evaluation, bump-usage) via a shared tab_field runner; wired into mod/client/dispatch
assets/openapi.yaml the 11 card routes declared

built == wired (the central trap)

The card fields are not merely persisted — they are hydrated and applied:

  • restore reads them from TabState onto the runtime tab (headless + GUI);
  • persist writes them back (explicit, not ..default());
  • the main-loop drain applies the four queues (pending_assignment/parent/ rehome/card_changes) onto the runtime tab, mirroring the existing
    context/meta drain.

Proven by round-trip integration tests (real TCP server via spawn_server):
POST a card route → 200, the value is mirrored into the snapshot, queued
for the drain
, and comes back out on /tabs. Covered: assignment
round-trip, current-task append + currentTaskLog surfacing, bump-usage
increment + usageCount surfacing, rehome 400-on-bad-state.

Verification (all green)

  • cargo build headless,energy ✓ · headless,energy,catbus ✓
  • cargo test headless,energy,catbus → 501 passed, 0 failed
  • cargo clippy (nursery=deny) headless,energy ✓ · headless,catbus ✓ · gui,energy,catbus ✓ (GUI parity proven — no allow added)
  • cargo fmt --check
  • openapi.yaml parses, 11 card paths present

Deliberate deviations (flagged for review)

  1. role_of + parse_assignment are foundation helpers published ahead of
    their consumer
    (commit 82d16e1). Downstream branches (task/aligator/catalog)
    each carried a private copy and drop theirs to consume this one after rebase
    (coordination MAS/tichef). Both carry a documented #[allow(dead_code)] — the
    same foundation-allow idiom upstream already uses for dashboard_url_for_role
    / rehome_badge; the allow comes off when the first in-tree consumer lands.
  2. is_rehome_state inlined the 4 slugs instead of porting mx's GUI-only
    RehomeStep/REHOME_STEPS struct (labels/badges are dashboard concerns).
    Same validation, no dead struct.
  3. Pre-existing, out-of-scope: cargo clippy --features gui,…,pets trips a
    suboptimal_flops nursery lint in src/pet.rs:1022 — byte-identical at the
    base commit 432bcc0, under the unrelated pets feature. Not touched.
    The GUI branches of app.rs are validated via --features gui,energy,catbus.

Not done here (follow-up candidates)

  • The parent_tab_id stamping from dispatch --new (the delegate) is not wired
    to auto-POST /parent; the route + field + CLI exist, the auto-stamp on spawn
    is a separate change.

a-biskoazh and others added 3 commits September 2, 2026 17:27
Foundation for the mx feature set re-homed onto modular-main: the hook-immune,
persisted agent-card schema — `assignment`, `specialty`, `orchestrator`,
`objective`, `current_task` (bounded permalog), `rounds_active`, `evaluations`
(bounded ring), `usage_count`, `conventions`, `parent_tab_id`, `rehome_status`
— plus the `RoundsActive` / `Eval{Tokens,Scores}` / `Evaluation` types. Fields
are serde-optional (old tabs.json loads clean). Readers (/tabs expo) and writers
(set-* CLIs) land in the following commits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second half of the mx agent-card re-home onto modular-main (fields + types
landed in 432bcc0). Wires the eleven persisted, hook-immune fields —
assignment, specialty, orchestrator, objective, current_task (bounded
permalog), rounds_active, evaluations (bounded ring), usage_count,
conventions, parent_tab_id, rehome_status — end to end:

- lib.rs: append_current_task / append_evaluation / bump_usage /
  parse_conventions helpers (+ CURRENT_TASK_LOG_MAX / EVALUATIONS_MAX).
- api.rs: CardChange enum, card_route_verb, is_rehome_state; SnapshotTab
  +11 fields, TabInfo +11 (camelCase currentTaskLog/roundsActive/usageCount,
  snake for the rest); four owner-drain queues (assignment/parent/rehome/
  card) + inits; route arms (master-token only, like /context).
- api/cards.rs: the assignment/parent/rehome/card_verb/evaluation/bump-usage
  setters (mirror into the snapshot + queue for the drain).
- headless.rs & app.rs (GUI parity): the card fields on the runtime tab,
  restored from TabState on load, written back on persist (the
  ..default() would otherwise wipe them), mirrored into the snapshot
  builder, and drained from the four queues onto the runtime tab — so the
  fields are hydrated AND applied, not just persisted.
- api/tabs.rs: populate the card fields on /tabs (currentTaskLog=current_task).
- cli: set-assignment / set-rehome-status + the eight card verbs (shared
  tab_field runner), wired into mod/client/dispatch.
- openapi.yaml: the eleven card routes.

Round-trip tests prove built==wired: POST a card route → 200, the value
is mirrored, queued for the drain, AND comes back out on /tabs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
role_of (a tab's role, derived from its assignment) and its sole dependency
parse_assignment (`"[<project>:]<phase>/<role>"` → parts) belong to the
agent-card foundation: downstream branches (task, aligator, catalog) each
carried a private copy, and drop theirs to consume this one after rebase
(coordination MAS/tichef). parse_assignment is `pub(crate)` so a branch that
needs project derivation can call it directly rather than re-declaring it.

Both carry a documented `#[allow(dead_code)]`: they're published ahead of
their first in-tree consumer (API-before-consumer sequencing, no bug masked) —
the same foundation-allow idiom upstream already uses for dashboard_url_for_role
/ rehome_badge. The allow comes off when a consumer lands. Canonical bodies
lifted verbatim from mx api/mod.rs; unit-tested (role after optional project).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 48.64479% with 360 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.38%. Comparing base (239178d) to head (82d16e1).

Files with missing lines Patch % Lines
src/cli/set_card.rs 0.00% 85 Missing ⚠️
src/api/cards.rs 45.63% 81 Missing ⚠️
src/app.rs 12.50% 77 Missing ⚠️
src/cli/tab_field.rs 55.97% 59 Missing ⚠️
src/lib.rs 56.41% 17 Missing ⚠️
src/cli/set_rehome.rs 45.83% 13 Missing ⚠️
src/cli/client.rs 0.00% 10 Missing ⚠️
src/cli/dispatch.rs 0.00% 10 Missing ⚠️
src/api.rs 97.27% 4 Missing ⚠️
src/cli/set_assignment.rs 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #43      +/-   ##
==========================================
- Coverage   52.41%   52.38%   -0.03%     
==========================================
  Files          92       97       +5     
  Lines       28268    28969     +701     
==========================================
+ Hits        14816    15176     +360     
- Misses      13452    13793     +341     
Flag Coverage Δ
rust 52.38% <48.64%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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