Skip to content

feat(actor): v0.6.20 — per-user Actor threading + scoped config resolution#286

Merged
Shooksie merged 3 commits into
mainfrom
feat/actor-thread
Jun 29, 2026
Merged

feat(actor): v0.6.20 — per-user Actor threading + scoped config resolution#286
Shooksie merged 3 commits into
mainfrom
feat/actor-thread

Conversation

@Shooksie

Copy link
Copy Markdown
Contributor

What

Threads an opaque per-user Actor (animus-protocol v0.1.25) through the kernel so config resolution + workflow runs are actor-scoped. Kernel stays user-agnostic (relays the actor, plugins scope). actor=None = byte-for-byte today's global behavior.

  • Repin all animus-protocol deps → v0.1.25 + add animus-actor.
  • Per-actor compiled-config cache re-key ((PathBuf, ActorCacheKey)) — proven no cross-actor leak.
  • WorkflowServiceApi::run resolves default-ref/phase-plan/skip/retry from the actor's config partition; actor persisted per-run (workflows.actor) so lifecycle transitions re-resolve consistently.
  • Control/dispatch relay + detached-runner env handoff; WU-G: actor pinned on the per-session animus MCP server (--actor-jsonpinned_actor).

Verification

build/clippy clean; cargo test 1217 pass / 2 pre-existing fail (decision_gate::workflow_*, confirmed on base); codex 0 P1.

Deferred (tracked)

Per-tool MCP enforcement (subject/queue protocol actor fields → TASK-132 consumption); --actor-json argv exposure P2 (low-risk single-tenant; matches --agent-id precedent).

🤖 Generated with Claude Code

Shooksie added 3 commits June 29, 2026 10:10
…onfig cache

Repin all v0.1.24 animus-protocol git deps to v0.1.25 and add the new
zero-dep `animus-actor` crate. v0.1.25 additively adds `actor: Option<Actor>`
to config/control/runner/session request types. control-protocol (v0.1.13 ->
v0.1.25), workflow-runner-protocol (v0.5.3 -> v0.1.25) and subject-protocol-wire
move with it (wire must share control's subject-protocol rev); queue +
subject-protocol-v05 stay on the matched v0.5.10 pair.

WU-C: thread `actor: Option<&Actor>` through resolve_plugin_base ->
load_via_resident -> config_load_call (serialized into config/load params) and
load_workflow_config[_with_metadata]. Re-key the compiled-config cache by
(project_root, ActorCacheKey) and fold the actor key into compile_token so one
user's compiled config can never be served to another; invalidate_compiled
clears every actor partition for a root. ActorCacheKey uses unambiguous JSON
(no delimiter-collision between distinct identities).

WU-D: relay actor through the control surface (struct passthrough) and populate
the runner WorkflowExecuteRequest.actor in execute.rs. The daemon control path
spawns a detached runner child that rebuilds its request from the persisted
record, so the authenticated actor is relayed to that child via a trusted
daemon->child env handoff (WORKFLOW_ACTOR_ENV) carried in the runner overrides.

TRUST BOUNDARY: the actor is set ONLY from the authenticated control request;
never synthesized from local CLI context, workflow YAML, agent output, or
subject content.

Tests: per-actor cache isolation (no cross-leak), actor=None == global,
invalidate clears all partitions, claim-order independence, delimiter-collision
resistance, and the detached-runner actor env round-trip.
… actor to the MCP sidecar

TASK 1 (resolve the deferred bootstrap P2): thread the transport-asserted
Actor through the workflow run/bootstrap + the phase-plan / config / retry
resolution it calls, so a user's PRIVATE workflow (visible only in that actor's
config_source partition) resolves at run-time, not from the global view.

- `WorkflowServiceApi::run(input, actor: Option<&Actor>)`: actor-scoped
  default-workflow-ref / phase-plan / skip-guard / retry resolution. actor=None
  == today's global behavior. Both FileServiceHub + InMemory impls + all callers
  updated (system/local/test callers pass None; the control-routed detached
  start passes the run's actor via DetachedRunnerOverrides).
- Added actor-aware variants (old fns delegate to None): `resolve_phase_plan_
  for_workflow_ref_for_actor`, `load_workflow_config_or_default_for_actor`,
  `load_agent_runtime_config_*_for_actor`.
- Persist the actor on the run so EVERY later lifecycle transition (resume /
  pause / cancel / complete / fail / mark_* / resolve_merge_conflict) re-resolves
  from the same partition — otherwise a private workflow starts then fails at the
  next transition. Stored in a kernel-owned `workflows.actor` SQLite column (NOT
  the protocol record); `save()` switched from INSERT OR REPLACE to an ON CONFLICT
  upsert so the column survives every later save. Test seam gains per-(root,actor)
  base injection.

TASK 2 (WU-G): relay the actor to the per-agent `animus mcp serve` sidecar so an
agent's MCP tool calls can scope to the user (per-user integrations / subject /
queue). The built-in MCP server is spawned PER AGENT SESSION (runtime_contract
mcp.stdio.command), so the actor reaches it per-agent-spawn:
- `inject_default_stdio_mcp_for_agent(.., actor)` appends `--actor-json` to the
  default serve args (in-tree ad-hoc callers pass None; the out-of-tree runner
  passes WorkflowPhaseRunRequest.actor).
- `animus mcp serve --actor-json` parses the Actor and pins it on AoMcpServer
  (`pinned_actor`), exposed via `pinned_actor()`; `run_tool` (the single tool
  choke point) emits per-user audit. Full per-tool ENFORCEMENT (scoping the
  underlying subject/queue/integration RPCs) is the consumer-side change tracked
  separately.

TRUST BOUNDARY: the actor is sourced ONLY from the authenticated run/control
request, never from workflow YAML, agent output, or subject content.

Tests: actor-private workflow resolves for its actor and NOT for None/another
actor; run() persists the actor and it survives a lifecycle save; --actor-json
clap parse; inject appends/omits --actor-json; actor round-trips through the
serve arg.
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
animus-docs Ready Ready Preview, Comment Jun 29, 2026 5:54pm

Request Review

@Shooksie
Shooksie merged commit 78f44f2 into main Jun 29, 2026
12 of 13 checks passed
@Shooksie
Shooksie deleted the feat/actor-thread branch July 4, 2026 23:15
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