# Context Handoff in Orquestra

Orquestra keeps agents focused by making context explicit. Agents do not pass a whole chat history to the next agent. They pass durable artifacts on disk, and each new stage reads only the files declared for that stage.

## Quick path

1. The current agent writes its result to `work/artifacts/<feature_id>/`.
2. From the active Pi session, `/orquestra-stage <stage> [feature_id]` calls `scripts/run_stage.py`.
3. `run_stage.py` starts a fresh Pi process.
4. The new agent receives only the `input` paths declared in `harness/workflow.stages.yml`.
5. The new agent writes its own output artifact.
6. `scripts/agent_status.py` and `scripts/verify.sh` enforce stage order and gates.
7. When the `close` stage completes, `scripts/close_feature.py <feature_id>` runs automatically to validate gates, update the backlog, commit and push if a remote repo is configured.

## Mental model

```text
Agent A
  reads its stage inputs
  writes one durable artifact
        │
        ▼
work/artifacts/F-001/agent-a-output
        │
        ▼
run_stage.py starts a fresh Pi process
        │
        ▼
Agent B
  reads only declared inputs, including Agent A's artifact if relevant
  writes its own artifact
```

The agents “talk” through files, not through memory-heavy chat context.

## Why fresh processes matter

A single long Pi session naturally accumulates chat, tool output, false starts, and old assumptions. That causes two problems:

| Problem | Orquestra answer |
|---|---|
| The next agent gets distracted by old context | Start the next stage with `--no-session --no-context-files` |
| Token usage grows until compaction | Each stage starts with a small prompt and declared files |
| Claims become hard to verify | Only artifacts on disk count as handoff evidence |
| Agents can skip gates in chat | `agent_status.py` validates stage owner and prerequisites |

## What a stage receives

Each stage receives three kinds of context:

1. **Harness rules** — always read first.
   - `AGENTS.md`
   - `harness/agents.matrix.yml`
   - `harness/workflow.stages.yml`
   - `harness/contracts/handoff.md`

2. **Declared stage inputs** — from `harness/workflow.stages.yml`.

3. **Selected Engram memory** — only when the agent performs a narrow search for a concrete need.

The full previous chat is not valid input.

## Example: design to build

`architect` receives product/spec context:

```yaml
- name: design
  owner: architect
  input:
    - work/current.md
    - spec/product.md
    - spec/tech.md
    - spec/acceptance.md
  output:
    - work/artifacts/<feature_id>/architect.md
```

It writes:

```text
work/artifacts/F-001/architect.md
```

Then `implementer` starts fresh from the active Pi session:

```text
/orquestra-stage build F-001
```

Equivalent shell form:

```bash
python3 scripts/run_stage.py build --feature-id F-001
```

The generated prompt gives it only:

```yaml
- name: build
  owner: implementer
  input:
    - work/current.md
    - spec/product.md
    - spec/tech.md
    - spec/acceptance.md
    - work/artifacts/<feature_id>/architect.md
  output:
    - work/artifacts/<feature_id>/implementer.md
```

So the implementer knows the design result, but not the architect's full chat.

## Example: build to review

The implementer writes evidence:

```text
work/artifacts/F-001/implementer.md
```

A minimal implementer artifact should answer:

```markdown
# Implementer Evidence

## Changed files
- project/app.py
- tests/test_app.py

## What changed
- Added ticket creation validation.

## Checks
- `python3 -m unittest discover -s tests -v` passed.

## Notes for reviewer
- Main behavior lives in `project/app.py:create_ticket`.
```

Then reviewer starts fresh:

```text
/orquestra-stage review_gate F-001
```

Reviewer input is only:

```yaml
input:
  - work/current.md
  - spec/acceptance.md
  - work/artifacts/<feature_id>/implementer.md
```

Reviewer does not need the architect's whole reasoning unless the workflow explicitly declares it. If reviewer needs more, it blocks and asks for a specific artifact/path.

## Example: security and QA reuse only relevant context

Security does not need all acceptance prose plus every design note. It needs the implementation evidence and review result:

```yaml
- name: security_gate
  owner: security
  input:
    - work/current.md
    - work/artifacts/<feature_id>/implementer.md
    - work/artifacts/<feature_id>/reviewer.json
```

QA needs acceptance criteria and approved gate context:

```yaml
- name: qa_gate
  owner: qa
  input:
    - work/current.md
    - spec/acceptance.md
    - work/artifacts/<feature_id>/implementer.md
    - work/artifacts/<feature_id>/reviewer.json
    - work/artifacts/<feature_id>/security.json
```

That is the core rule: give each agent the smallest context that lets it do its job.

## Anti-cheating controls

```text
run_stage.py
  ├─ starts fresh Pi process
  ├─ disables previous session/context files
  └─ injects only declared input/output paths

agent_status.py
  ├─ validates stage owner
  ├─ requires feature_id for real stages
  ├─ rejects gated stages when prerequisite artifacts are missing
  └─ keeps visible runtime status

orquestra-status extension
  ├─ blocks writes outside allowed directories: project/, tests/, work/, backlog/, spec/, harness/, scripts/, platforms/, docs/
  ├─ blocks product/test writes outside implementer build stage
  └─ blocks product code in repository root

verify.sh
  ├─ validates harness structure
  ├─ validates backlog/runtime JSON
  ├─ validates Engram availability
  └─ rejects done features without approved gate artifacts
```

Chat-only claims do not pass any gate. The agent must write evidence to disk.

## Ticket lifecycle commands

Do not edit `backlog/features.json` directly. Use the repository scripts:

```bash
# Create a pending ticket interactively.
python3 scripts/new_ticket.py

# Select exactly one pending ticket and promote it to in_progress.
python3 scripts/new_ticket.py --start F-048

# Repair the deprecated `review` gate key in imported/legacy tickets.
python3 scripts/new_ticket.py --normalize-gates

# After reviewer, security and QA approve, close and commit the ticket.
python3 scripts/close_feature.py F-048
```

`--start` refuses to run when another feature is already `in_progress`. `verify.sh` also rejects a runtime marked `running` when the matching backlog feature is still `pending`.

## What Engram is for

Engram is durable memory for reusable facts, not a replacement for stage artifacts.

Each stage must save to Engram only when it produced durable knowledge.

Use Engram for:

- stable project decisions,
- bug fixes,
- non-obvious discoveries,
- reusable conventions or patterns,
- configuration changes,
- repeated gotchas,
- environment facts,
- lessons learned across features.

Do not use Engram for:

- replacing `implementer.md`,
- hiding gate evidence,
- routine progress,
- command output dumps,
- artifact summaries,
- passing huge summaries to every stage,
- bypassing declared workflow inputs.

A good Engram lookup is narrow:

```text
Search: "orquestra project root product files rule"
Use result only if it affects this stage.
```

A bad lookup is broad:

```text
Search: "everything about this project"
```

## Updating an installed project safely

From the Orquestra source checkout:

```bash
/path/to/orquestra/scripts/install.sh /path/to/project
cd /path/to/project
./scripts/verify.sh
```

The installer updates harness-owned files and preserves project-owned progress files when they already exist:

```text
backlog/features.json
spec/*
work/current.md
work/history.md
work/runtime-status.json
project/*
work/artifacts/*
```

That means an existing project can adopt fresh-stage handoff without losing its current feature state.
