Skip to content

feat: studio control-plane — agent-lifecycle + vendored oabctl + MCP (slice-0) - #2

Merged
brettchien merged 13 commits into
mainfrom
feat/agent-lifecycle-core
Aug 9, 2026
Merged

feat: studio control-plane — agent-lifecycle + vendored oabctl + MCP (slice-0)#2
brettchien merged 13 commits into
mainfrom
feat/agent-lifecycle-core

Conversation

@brettchien

@brettchien brettchien commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Realizes the plan: Studio becomes the control-plane, built on a vendored oabctl, with an MCP surface so an agent operates it first-class. One repo, four crates:

        agent-lifecycle    ← canonical 6-state + 4-axis discriminator (ADR-1)
           ▲        ▲
   crates/oabctl   studio-cp   ← read/write model over oabctl (ADR-2)
   (vendored)        ▲
                  crates/oab-mcp  ← MCP server: read+write as tools (stdio)

In this PR — read + write + MCP (ADR-2 slice-0)

  • crates/agent-lifecycle — 6-state model, 4-axis discriminator (incl. latching identity_verified), RuntimeDriver (projection-only this slice), ECS projection, tests.
  • crates/oabctlvendored from openabdev/openab operator/ @ d64c678 (MIT, attributed in VENDORED.md). Studio-local additions are additive and listed there: a config-free studio_api (parse/scale/delete) + one visibility widening.
  • crates/studio-cp — the read/write seam:
    • readobserve_services / observe_deployment; per-instance ECS status → canonical 6-state; the generic Deployment read-model (counters + per-instance phase); read-only studio-cp CLI.
    • writeapply_deployment (YAML → programmatic apply → ApplyReport), scale_deployment (0/1), delete_deployment. Config-free: cluster/namespace explicit, control-plane bucket from env/account — no ~/.oabctl/config.toml.
  • crates/oab-mcp — hand-rolled rmcp 1.7 ServerHandler over stdio, six tools: deploy_list, deploy_get, get_agent_states, deploy_apply, deploy_scale, deploy_delete. See its README.md.
  • Workspace wiring + CI: build+test whole workspace, plus a smoke step that starts oab-mcp and drives a real MCP initializetools/list over stdio.

Next slices

  • Live ECS driver: DescribeTasks-based observe + the state() convenience (deferred out of the projection-only trait here).
  • k8s driver (aligns with openab ecs-control-plane.md Phase 3), identity/lease/epoch.
  • Richer MCP results (structured apply report, per-instance detail).

Verificationcrates/agent-lifecycle (zero deps) is built + tested + linted locally: cargo test 10 pass, cargo clippy -D warnings clean, cargo fmt --check clean. The oabctl / studio-cp / oab-mcp crates pull in aws-sdk-ec2, whose single-crate rustc peak exceeds the authoring box's RAM (3.7 GiB, no swap), so those are CI-verified (ubuntu-latest): whole-workspace build + test and the MCP stdio smoke test are green.

brettchien and others added 2 commits August 8, 2026 16:16
Implements docs/adr/agent-lifecycle.md:
- AgentState (6), Discriminator (4 axes incl. latching identity_verified),
  classify() with the Starting/Unhealthy split the latch resolves.
- IdentityLatch: CP-owned monotonic identity_verified bit.
- RuntimeDriver trait: observe -> project -> classify.
- EcsDriver: ECS lastStatus/desiredStatus/healthStatus/lease/cordon projection
  (DescribeTasks wiring deferred to a later slice).
- Unit tests incl. F1 (latch), superseded=>Paused, Unknown=>Unhealthy, Stopping.

NOT compile-verified locally (no cargo toolchain on the authoring runtime) —
needs cargo test in CI / on Brett's box.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vendor the oabctl crate (ECS provisioner CLI+lib) from openabdev/openab
operator/ @ d64c678 (MIT, attributed in crates/oabctl/VENDORED.md) so Studio can
build control-plane actions + an MCP surface on it in one repo instead of across
repos. Wire it into the workspace alongside agent-lifecycle.

Add GitHub Actions CI (fmt/clippy on our crates; build+test the whole
workspace) — the authoring runtime has no cargo toolchain, so CI is the
compile/test verification for both the vendored crate and agent-lifecycle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@brettchien brettchien changed the title feat(agent-lifecycle): canonical 6-state core + ECS driver (slice-1) feat: studio control-plane — agent-lifecycle + vendored oabctl + MCP (slice-0) Aug 8, 2026
brettchien and others added 11 commits August 8, 2026 17:58
No rustfmt on the authoring runtime, so style is informational for now; the
hard gate is that the whole workspace (vendored oabctl + agent-lifecycle)
compiles and tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
How oabctl exposes to Studio (PR #2's real integration point):
- oabctl: add public library status API crates/oabctl/src/status.rs
  (ServiceStatus struct + service_status()) — the data half of `oabctl get`,
  returning structs instead of printing a table. Additive + upstream-shaped.
- studio-cp: new downstream crate depending on oabctl + agent-lifecycle;
  observe_services() consumes oabctl::service_status. This is the seam where
  the 6-state mapping and a future MCP surface attach.

oabctl stays clean (additive pub API only); Studio-specific logic lives
downstream in studio-cp — keeping the vendored crate upstream-contributable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- oabctl: add InstanceStatus + instance_status() (ListTasks + DescribeTasks) —
  the per-Task granularity ADR-2 Claim 3 requires (DescribeServices is
  service-level only). Additive, upstream-shaped.
- studio-cp: instance_phase() maps an ECS InstanceStatus onto AgentState via
  agent-lifecycle's EcsDriver (last_status/health_status → discriminators →
  classify). Admission/lease are CP-level (not ECS-observable) and default here.
- Tests for the mapping (ACTIVATING->Starting, RUNNING+healthy->Running,
  RUNNING+unhealthy(verified)->Unhealthy, desired-stopped->Stopping).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ADR-2 §4 read-model slice-2, in studio-cp:
- Deployment { name, namespace, desired, current, ready, instances:[InstancePhase] }
  — Deployment-level counters (NOT an AgentState) + per-Instance phase.
- build_deployment(ServiceStatus, [InstanceStatus]) — pure aggregation; ready =
  count of Running instances.
- observe_deployment() wires service_status + instance_status end-to-end.
- latched_verified(): one-shot approximation of the identity_verified latch
  from current lastStatus (real latch needs CP-persisted history).
- Test for the aggregation (ready count + per-instance phases).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ADR-2 read-tools front-end prototype:
- studio-cp bin: 'list' -> Deployments + counters (deploy_list); 'get <service>'
  -> one Deployment's counters + per-Instance phase (deploy_get). Read-only;
  writes wait on ADR-3 authz. Cluster from $OAB_CLUSTER (default oab).
- tokio dep for the async runtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Authoring runtime now has cargo+rustfmt; format ecs.rs so the CI fmt
step is clean. Whitespace-only; 10 unit tests still pass, clippy -D
warnings clean.
Adds the ADR-2 write model as thin passthroughs to oabctl, mirroring the
read-side observe_* seam:

- oabctl: new additive `studio_api` module (parse_manifests / scale /
  delete) — a structured, non-interactive surface over the CLI-oriented
  internals so downstream calls a lib API instead of shelling out. No
  upstream behaviour changed; recorded in VENDORED.md.
- studio-cp: apply_deployment (parse YAML -> programmatic apply ->
  ApplyReport), scale_deployment, delete_deployment.

Next: MCP server (crates/oab-mcp) exposing read+write as tools.
Compile-blind locally (aws-sdk-ec2 exceeds this box's RAM); relying on CI.
… MCP)

Two things, together so CI compiles them as one unit:

1. Fix wiring the prior commit missed (studio_api.rs was committed but its
   `pub mod studio_api;` + the studio-cp write fns + VENDORED.md note were
   not, so the write seam never actually compiled). Now included:
   - oabctl: pub mod studio_api; (parse_manifests/scale/delete)
   - studio-cp: apply_deployment / scale_deployment / delete_deployment
   - VENDORED.md: record the additive studio_api module

2. New crate crates/oab-mcp — a hand-rolled rmcp 1.7 ServerHandler (stdio)
   exposing the read+write model as six MCP tools: deploy_list, deploy_get,
   get_agent_states, deploy_apply, deploy_scale, deploy_delete. Thin dispatch
   into studio-cp; owns only the JSON wire shape. Added to the workspace.

Still compile-blind locally (aws-sdk-ec2 > this box's RAM); CI is the gate.
…ist)

Compiling isn't running. Add a CI step that starts the built binary and
drives a real MCP stdio handshake (initialize -> initialized -> tools/list),
asserting all six tools are advertised. Needs no AWS creds — the catalog is
static; AWS is resolved lazily on real tool calls.
Addresses PR#2 review items 1-5,7:

1. Config-free scale/delete: studio_api.scale now drives ECS UpdateService
   via ecsctl directly (cluster/namespace explicit, size 0|1 enforced);
   studio_api.delete resolves the control-plane bucket from env/account and
   reuses delete::run_with_bucket (widened to pub(crate)). Neither reads
   ~/.oabctl/config.toml anymore. Seam + MCP deploy_scale (name/cluster/
   namespace, size 0|1) updated to match.
2. Drop RuntimeDriver::observe + the state() convenience (only called by each
   other, never externally) and remove EcsDriver's unimplemented! stub — the
   trait is projection-only this slice, no shipped panic. Verified locally:
   agent-lifecycle 10 tests + clippy green.
3. oab-mcp unit tests: tool catalog (6 named) + deployment_json wire shape.
4. apply_deployment error carries the structured ApplyErrorKind.
7. oab-mcp README (tools, run, env, mcp.json, 0/1 scale semantics).

VENDORED.md updated for the studio_api rewrite + run_with_bucket visibility.
oabctl/studio-cp/oab-mcp remain compile-blind locally; CI is the gate.
So a runtime that can't compile oab-mcp locally (aws-sdk-ec2 > small-box RAM)
can fetch the CI-built binary and drive it as an MCP client.
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