# Personal Orchestrator Compound Action Spine Implementation Plan

> **For Hermes:** Use `compound-work` or `subagent-driven-development` to implement this plan task-by-task. Treat this as the source-of-truth implementation contract for upgrading the Personal Orchestrator Action Manager card template and routing behavior.

**Date:** 2026-05-27

**Source prompt:** Connor asked for an implementation-ready plan for making the Personal Orchestrator use Hermes Compound Engineering as its “action spine”: detect candidate work, classify altitude, make vague nudges approvable, autonomously do safe local work, ask only at true decision gates, review before surfacing done, and capture learning.

**Related proof:** Prior quick consult: `/root/personal-orchestrator/consults/2026-05-27T20-28-31.779665-00-00/CONSULT.md`

**Goal:** Upgrade the Personal Orchestrator so every action proposal is routed through a Compound Engineering phase and rendered as an approval-ready card with problem, why now, implementation outline, autonomy lane, risk, done condition, and proof path.

**Architecture:** Keep the existing Personal Orchestrator faculty/synthesis pipeline. Add a thin Compound Action Spine inside/near `runners/action_manager.py`: normalize candidate cards, classify them into `strategy | brainstorm | plan | work | review | learn`, enrich the rendered card fields, route safe local work autonomously, and require proof/review before any “done” surface. Do not make PO busy; suppression remains a first-class action.

**Tech stack / surfaces:** Python, pytest, markdown/JSON artifacts under `/root/personal-orchestrator/runs/*`, Action Manager in `runners/action_manager.py`, tests in `tests/test_action_manager.py`, delegation/lifecycle state under `state/` and `delegations/`.

---

## Requirements

### R-001: Detect candidate work from existing faculties and sources

PO must continue taking candidate work from existing faculty and synthesis outputs: Open Tabs, cron outputs, Gmail/calendar context assets, GBrain/context assets, feedback ledger, source health, and collaborator synthesis.

### R-002: Classify Compound Engineering altitude

Every action candidate must include one `compound_phase`:

- `strategy` — clarify direction, principles, tradeoffs, priorities.
- `brainstorm` — explore options when solution space is under-shaped.
- `plan` — create a traceable implementation/spec/delegation plan.
- `work` — execute a bounded safe task or queue a goal packet.
- `review` — audit correctness, evidence, risk, noise, or proof.
- `learn` — convert repeated patterns into skills, templates, source adapters, or durable memory.

### R-003: Make vague nudges approvable

Every surfaced proposal must render these fields:

- Problem being solved.
- Why now.
- Proposed implementation outline.
- Compound phase.
- Autonomy lane.
- Risk class.
- Done condition.
- Proof path / proof requirement.
- Evidence/source refs.
- Stop conditions / approval gates.

### R-004: Autonomously do safe local work

For low-risk local candidates, PO may act without asking by creating local artifacts only:

- diagnostic notes;
- draft specs;
- repair notes;
- local proof/status logs;
- queued delegation packets;
- local candidate implementation plans;
- source-near adapter proposals.

It must not silently send messages, mutate email/calendar/finance, publish externally, delete data, deploy, or make irreversible changes.

### R-005: Ask only at true decision gates

The card must require approval for:

- external side effects;
- finance/email/calendar/messaging;
- destructive changes;
- deployments;
- ambiguous priorities;
- changes to user-facing behavior with meaningful risk;
- anything with insufficient evidence.

### R-006: Review before “done”

No candidate should be marked `done` unless the proof packet exists and a review gate has passed. For this implementation, the minimum review is an Action Manager self-check; for higher-risk cards, `compound-review` is required.

### R-007: Capture learning

Repeated successful repairs or repeated noisy proposals should route to `learn` and produce one of:

- Hermes skill patch proposal;
- card template update proposal;
- source adapter rule;
- suppression heuristic;
- GBrain fact candidate;
- Faculty Experience Ledger entry.

### R-008: Preserve suppression as intelligent action

The Action Manager must still suppress low-impact, duplicate, weak-evidence, or already-delegated cards. “No action” is allowed and should be explained when useful.

---

## Non-goals

- Do not rewrite the full Personal Orchestrator architecture.
- Do not run a new full-faculty E2E pass just to implement the template upgrade.
- Do not mutate external systems.
- Do not publish private/raw context assets.
- Do not force every card into action; suppression remains valid.
- Do not create opaque card IDs as the only UX; natural-language feedback and numbered nudges should continue to work.

---

## Current implementation findings

Relevant existing surfaces:

- `runners/action_manager.py`
  - `ActionCandidate` currently has fields such as `action_id`, `source_card_id`, `title`, `action_class`, `routing_lane`, `risk_class`, `status`, `evidence`, `expected_benefit`, `done_condition`, `proof_required`, `scores`, `capability_id`, and `routing_rationale`.
  - It already models routing lanes (`suppress`, `remember`, `ask`, `suggest`, `draft`, `local_safe_work`, `delegate`, `modify_local_system`, `approval_required_external`) and risk classes.
  - It already renders `# Action Manager` markdown.
- `tests/test_action_manager.py`
  - Existing tests cover lane mapping, external approval gating, suppression, capability registry rendering, lifecycle events, and proof rendering.
- `IMPLEMENTATION_STATUS.md`
  - Confirms Action Manager artifacts are emitted and tested in prior smoke checks.

The implementation can therefore be incremental: enrich schema/rendering/classification rather than replacing the pipeline.

---

## Implementation units

### U-001: Add Compound phase vocabulary and validation

**Goal:** Make Compound Engineering phase a first-class field on every `ActionCandidate`.

**Traces to:** R-002, R-003

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py`
- Modify: `/root/personal-orchestrator/tests/test_action_manager.py`

**Steps:**

1. Add constant:

```python
COMPOUND_PHASES = {"strategy", "brainstorm", "plan", "work", "review", "learn"}
```

2. Add `compound_phase: str = "work"` to `ActionCandidate`.

3. Validate in `ActionCandidate.__post_init__`:

```python
_validate_choice("compound_phase", self.compound_phase, COMPOUND_PHASES)
```

4. Ensure `to_dict()` includes `compound_phase` automatically via `asdict`.

5. Add test: a candidate created from a local diagnostic card defaults to `work` or the inferred phase.

**Acceptance:** `pytest tests/test_action_manager.py -q` passes and JSON candidates include `compound_phase`.

---

### U-002: Implement phase inference from card content and lane

**Goal:** Route candidate altitude automatically when upstream cards do not provide it.

**Traces to:** R-002, R-003, R-008

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py`
- Modify: `/root/personal-orchestrator/tests/test_action_manager.py`

**Recommended helper:**

```python
def infer_compound_phase(card: dict, *, action_class: str, routing_lane: str, title: str) -> str:
    explicit = str(card.get("compound_phase") or card.get("workflow_phase") or "").strip().lower()
    if explicit in COMPOUND_PHASES:
        return explicit
    text = " ".join(str(x or "") for x in [title, card.get("claim"), card.get("done_condition"), card.get("evidence")]).lower()
    if routing_lane == "suppress":
        return "review"
    if "skill" in text or "template" in text or "learn" in text or "repeated" in text:
        return "learn"
    if "review" in text or "audit" in text or "verify" in text or "proof" in text:
        return "review"
    if "plan" in text or "spec" in text or "requirements" in text or "implementation" in text:
        return "plan"
    if "option" in text or "brainstorm" in text or "explore" in text:
        return "brainstorm"
    if "strategy" in text or "principle" in text or "priority" in text or "direction" in text:
        return "strategy"
    return "work" if routing_lane in {"local_safe_work", "delegate", "modify_local_system"} else "plan"
```

**Tests:**

- “write implementation plan” → `plan`.
- “audit proof packet” → `review`.
- “patch repeated pattern into skill/template” → `learn`.
- Suppressed low-value card → `review`.
- Explicit `compound_phase` wins.

**Acceptance:** Phase inference is deterministic and covered by tests.

---

### U-003: Enrich ActionCandidate with approvable card fields

**Goal:** Every card has enough detail for Connor to approve without asking “what exactly would happen?”

**Traces to:** R-003, R-005

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py`
- Modify: `/root/personal-orchestrator/tests/test_action_manager.py`

**Fields to add:**

```python
problem: str = ""
why_now: str = ""
implementation_outline: str = ""
approval_gate: str = ""
proof_path: str = ""
```

**Normalization rules:**

- `problem`: use upstream `problem`, else derive from `claim/title`.
- `why_now`: use upstream `why_now`, else concise evidence-based sentence.
- `implementation_outline`: use upstream `implementation_outline`, else phase-specific default.
- `approval_gate`: derive from risk/lane; “No approval needed for local artifact only” for safe local work; explicit approval for external/destructive/ambiguous work.
- `proof_path`: use upstream `proof_path`, else local artifact path expectation such as `runs/<run_id>/ACTION_MANAGER.md` or delegation proof path.

**Acceptance:** Rendered markdown includes all fields for every non-suppressed surfaced candidate.

---

### U-004: Upgrade markdown rendering to approval-ready card format

**Goal:** Make PO output cards immediately actionable and readable.

**Traces to:** R-003, R-005, R-006

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py`
- Modify: `/root/personal-orchestrator/tests/test_action_manager.py`

**Rendering shape:**

The rendered card should look like this:

- Heading: candidate title.
- Metadata: action id, compound phase, autonomy lane, risk, status.
- Body fields: problem, why now, implementation outline, done condition, proof required, proof path, approval gate, evidence, and score summary.

Do not rely on an opaque card id alone; the rendered card must explain what would happen and how it will be proven.

**Tests:** Extend `test_action_manager_render_includes_scores_and_proof` to assert the markdown contains `Problem`, `Why now`, `Implementation outline`, `Compound phase`, `Autonomy lane`, `Approval gate`, and `Proof path`.

**Acceptance:** Existing and new tests pass; rendered `ACTION_MANAGER.md` can be read as an approval queue.

---

### U-005: Add safe-local-work artifact/delegation packet stub

**Goal:** Allow low-risk local candidates to move beyond suggestion into prepared local action without side effects.

**Traces to:** R-004, R-005, R-006

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py` or add `/root/personal-orchestrator/runners/action_spine.py`
- Modify/Add tests in `/root/personal-orchestrator/tests/`

**Behavior:**

For candidates with:

- `risk_class == "low-risk"`; and
- `routing_lane in {"local_safe_work", "delegate"}`; and
- `compound_phase in {"plan", "work", "review", "learn"}`

create a local proof/prep artifact, not external execution:

```text
runs/<run_id>/action_spine/<action_id>/goal.md
runs/<run_id>/action_spine/<action_id>/status.json
runs/<run_id>/action_spine/<action_id>/proof.md
```

`goal.md` must include objective, source evidence, boundaries, acceptance criteria, validation command, and reporting expectations.

**Safety rule:** If candidate is external/destructive/ambiguous, write only an approval-needed card; do not create execution artifacts beyond a proposal.

**Acceptance:** Test creates a temp run directory and verifies safe local candidate writes goal/status/proof stubs; external candidate does not.

---

### U-006: Add review gate before marking done

**Goal:** Prevent PO from claiming completed work without proof.

**Traces to:** R-006

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py` or lifecycle helper.
- Modify: `/root/personal-orchestrator/tests/test_action_manager.py` or `tests/test_action_lifecycle_linkage.py`.

**Behavior:**

Add helper:

```python
def can_mark_done(candidate: ActionCandidate, *, proof_exists: bool, review_status: str = "") -> tuple[bool, str]:
    if not proof_exists:
        return False, "missing proof packet"
    if candidate.risk_class != "low-risk" and review_status != "passed":
        return False, "review gate required"
    return True, "done gate passed"
```

**Acceptance:** Tests show missing proof blocks done; high-risk card requires passed review; low-risk with proof can pass.

---

### U-007: Route repeated patterns to learning artifacts

**Goal:** Convert repeated repairs/noisy suggestions into durable learning instead of recurring nudges.

**Traces to:** R-007, R-008

**Files:**

- Modify: `/root/personal-orchestrator/runners/action_manager.py`
- Potentially add: `/root/personal-orchestrator/docs/templates/compound-learn-card.md`
- Tests in `/root/personal-orchestrator/tests/test_action_manager.py`

**Behavior:**

If card evidence/title mentions repeated pattern, template, skill, source adapter, suppression heuristic, or Connor feedback cluster:

- infer `compound_phase = "learn"`;
- set `implementation_outline` to a learning artifact proposal;
- set proof requirement to “skill/template/source-adapter patch proposal exists and cites source feedback.”

**Acceptance:** Test repeated-card fixture maps to `learn` and renders learning-specific proof.

---

### U-008: Wire Action Manager output into latest run artifacts

**Goal:** Ensure PO runs emit the upgraded card format and optional local action spine artifacts.

**Traces to:** R-001 through R-008

**Files:**

- Inspect/modify: `/root/personal-orchestrator/runners/observability_run.py`
- Inspect/modify: `/root/personal-orchestrator/runners/consult.py` if consult surfaces Action Manager cards.
- Tests: `/root/personal-orchestrator/tests/test_observability_run.py` and/or existing Action Manager tests.

**Steps:**

1. Locate where `ACTION_CANDIDATES.json` and `ACTION_MANAGER.md` are written.
2. Ensure new candidate fields are serialized.
3. Ensure markdown render includes new card fields.
4. If local action spine stubs are enabled, write them under the current run directory.
5. Do not break existing `synthesis.json` consumers; add fields backward-compatibly.

**Acceptance:** Smoke command emits upgraded markdown and JSON:

```bash
cd /root/personal-orchestrator
python3 runners/action_manager.py \
  --synthesis runs/latest/synthesis.json \
  --out-json /tmp/action-candidates-compound-spine.json \
  --out-md /tmp/action-manager-compound-spine.md
```

Expected:

- command exits 0;
- markdown contains `Compound phase`, `Problem`, `Why now`, `Implementation outline`, `Approval gate`, `Proof path`;
- JSON contains `compound_phase` for every candidate.

---

### U-009: Add docs and operator notes

**Goal:** Make future agents understand the Action Spine behavior.

**Traces to:** all requirements

**Files:**

- Update: `/root/personal-orchestrator/IMPLEMENTATION_STATUS.md`
- Add/update: `/root/personal-orchestrator/docs/action-spine.md`
- Optional update: relevant Hermes skill or PO faculty reference if implementation reveals reusable workflow.

**Docs must cover:**

- Compound phase definitions.
- Autonomy lane rules.
- Approval gates.
- Proof packet expectations.
- Safe local work boundaries.
- How Connor can approve: natural language, `do 1`, `do_this`, etc.
- Suppression/no-action as intelligent behavior.

**Acceptance:** Docs cite tests and smoke command outputs.

---

## Verification commands

Run from `/root/personal-orchestrator`:

```bash
python3 -m pytest tests/test_action_manager.py -q
python3 -m pytest tests/test_action_lifecycle_linkage.py tests/test_delegation_backlog.py -q
python3 runners/action_manager.py --synthesis runs/latest/synthesis.json --out-json /tmp/action-candidates-compound-spine.json --out-md /tmp/action-manager-compound-spine.md
python3 - <<'PY'
import json, pathlib
rows = json.loads(pathlib.Path('/tmp/action-candidates-compound-spine.json').read_text())
items = rows.get('candidates', rows if isinstance(rows, list) else [])
assert items, 'no candidates emitted'
for row in items:
    assert row.get('compound_phase'), row
md = pathlib.Path('/tmp/action-manager-compound-spine.md').read_text()
for term in ['Compound phase', 'Problem', 'Why now', 'Implementation outline', 'Approval gate', 'Proof path']:
    assert term in md, term
print('compound action spine smoke ok')
PY
```

If `runs/latest/synthesis.json` has no candidates, use a fixture synthesis file or add a unit test fixture rather than weakening the assertions.

---

## Review gate

Review level: **Tier 2 (`compound-review`)** because this changes the PO action-routing surface and could increase noisy/autonomous work if implemented poorly.

Review lenses:

1. **Correctness:** Every card gets valid phase/lane/risk/proof fields.
2. **Actionability:** A human can approve/reject without asking for missing implementation details.
3. **Safety:** External/destructive/ambiguous work cannot run without approval.
4. **Noise suppression:** Low-value cards are suppressed or batched; action spine does not create busywork.
5. **Proof:** Done requires proof packet and review gate.
6. **Backward compatibility:** Existing synthesis/action consumers still read JSON.

---

## Parallelization

Safe to parallelize:

- U-001/U-002 schema + inference with tests.
- U-004 rendering once U-001 field names are agreed.
- U-009 docs after schema names stabilize.

Do not parallelize:

- U-003 and U-004 if both touch the same render function.
- U-005 and U-008 until artifact paths are agreed.
- U-006 until lifecycle status semantics are confirmed.

---

## Stop conditions

Stop and ask Connor before continuing if:

- implementation requires sending messages, changing calendar/email/finance, publishing private PO outputs, or deploying services;
- existing Action Manager semantics conflict with this plan in a way that would break current nudges;
- test fixtures show all candidates become action/work and suppression disappears;
- the system starts creating opaque busywork artifacts without a clear proof path;
- the plan would require rewriting the full faculty/synthesis pipeline.

---

## Expected final proof packet

Implementation is done when the executor can point to:

- code diff for `runners/action_manager.py` and related wiring;
- tests added/updated;
- passing pytest output;
- smoke output files under `/tmp/` or a real run directory;
- one rendered `ACTION_MANAGER.md` example showing approval-ready fields;
- one safe-local-work goal/proof stub example;
- review notes from `compound-review`;
- updated docs/status file.

---

## Implementation-ready delegation prompt

Use this prompt if delegating to a fresh agent:

```text
Objective: Implement the Personal Orchestrator Compound Action Spine plan at /root/personal-orchestrator/docs/plans/2026-05-27-compound-action-spine-plan.md.

Done state: Action Manager candidates include compound_phase, problem, why_now, implementation_outline, approval_gate, proof_path; rendered cards are approval-ready; safe local work can create local proof/delegation stubs only; done transitions require proof/review; tests and smoke checks pass.

Boundaries: Work only under /root/personal-orchestrator unless explicitly approved. Do not send external messages, mutate calendar/email/finance, deploy, delete data, or publish private run artifacts. Preserve existing unrelated changes. Keep JSON backward-compatible.

Verification: Run the exact pytest and smoke commands in the plan. Save proof paths and command output in a status/proof artifact. Finish with a concise report listing files changed, tests run, proof paths, and any blocked items.
```
