theway-daemon 0.1.21

theway daemon — the single agent-runtime kernel (bin `thewayd`): harness assembly, local/sandbox tool policy, triggers/cron/session/DAG runtime, skills, MCP/LSP wiring, serving the gRPC/HTTP/MCP transports from theway-transport. Terminal UI lives in the theway-tui crate.
Documentation
# daemon/src/context — Context projection module

This module is the daemon-side entry point for turning a session into the
context bundle consumed by the agent harness. It reads the persisted session
log, derives a lineage block, and composes the system prompt. It never mutates
session entries.

## Components

| File | Responsibility |
| --- | --- |
| `mod.rs` | Module declarations and test bridge. |
| `system_prompt.rs` | Base system prompt + grouped tool inventory + working directory + memory + optional lineage block. |
| `lineage.rs` | Collapse lineage/handoff block (identity + tool guidance only). |
| `service.rs` | `ContextService::load(session) -> ContextBundle` single entry point. |

## Context flow

```text
Session entries (append-only log)
  -> session.build_context()            // core: entries -> AgentMessage list
  -> session.compact_context()          // core: read compact_context custom entry
  -> session.collapse_node_id()         // core: read collapseNodeId metadata
  -> read_session_metadata(...)         // daemon: session_metadata custom entries
  -> render_lineage(...)                // daemon: identity + tool guidance
  -> compose_system_prompt(...)         // daemon: intro + grouped tools + cwd + memory + lineage
  -> ContextBundle { system_prompt, messages }
```

`ContextBundle.messages` still contains `AgentMessage` values. The provider
request is materialized later by `theway_core::default_convert_to_llm`, which
maps the known custom summary roles to framed user text.

## Invariants

1. Session entries are the canonical log. Context projection only reads them.
2. The compact summary is injected exactly once, as a
   `collapse_context` custom message in `messages`.
3. The system prompt carries lineage identity and tool guidance only; it does
   not repeat `compactText`.
4. Raw transcripts stay out of the default context and remain available
   through `session_graph_read`.
5. The tool inventory is grouped by category; unknown tools fall into
   `Other`.
6. The harness introduction is customizable per session through the
   `harnessIntroduction` session metadata key.

The `<harness>` block carries four runtime-model descriptions before the
behavioral rules:

1. Session model: append-only message tree, compaction tail/summary, and
   virtualized tool results (`session_tool_result` / `session_tool_result_grep`).
2. Collapse model: repeated collapses are allowed; every collapse emits one
   bounded rolling compact summary with fixed components (goal, completed work,
   key decisions, next steps, critical context). Precision loss is expected.
   The lineage block records only the collapse event and node/session ids;
   full transcripts are read on demand through `session_graph_*`.
3. Exploration model: outline + offset/limit reads + grep before edits.
4. Graph and subagent orchestration principles: dependency-declared DAG nodes,
   file-disjoint parallel tasks, `dag_wait` harvesting, orchestrator-owned git
   history.

The composed prompt order is `<harness>` first, then `<tools>`, then
`<environment>`, then optional `<lineage>`.

## Editing rule

When a user asks to adjust one of the example prompts in this document, modify
the prompt-composition source code (`system_prompt.rs`, `lineage.rs`, or
`service.rs`), not the example text itself. The examples are renderings of the
source behavior; changing only the example would make this document diverge
from the actual system prompt.

## Example contexts

### 1. Normal session, no collapse lineage

```text
<harness>
You are theway, a minimal coding assistant running in a terminal.

Session model: the conversation is stored as append-only session entries ...
Exploration: read files before editing ...
Graph and subagent orchestration: dag_* tools ...
</harness>

<tools>
- Files: edit, git, ls, read, write
- Execution: bash
- Context & search: grep, outline
</tools>

<environment>
Current working directory: /home/user/project
<memory>
Remember: keep commit messages conventional.
</memory>
</environment>
```

`messages`:

```json
[
  { "role": "user", "content": "add a login page", "timestamp": 123 }
]
```

### 2. Collapse child session

After `/collapse`, the new session has a `compact_context` entry and
`collapseNodeId` metadata. The system prompt gains a lineage block but no
summary text:

```text
<harness>
You are theway, a minimal coding assistant running in a terminal.

Session model: ...
Exploration: ...
Graph and subagent orchestration: ...
</harness>

<tools>
- Files: edit, read, write
- Execution: bash
- Context & search: grep, outline
- Session graph: session_graph_attach, session_graph_list, session_graph_read, session_graph_status, session_graph_wait
</tools>

<environment>
Current working directory: /home/user/project
</environment>

<lineage>
## Session lineage

Collapse event:
  node id: node-01JEXAMPLE0000000000000000
  source session id: session-123
</lineage>
```

`ContextBundle.messages` before provider materialization:

```json
[
  {
    "type": "custom",
    "role": "collapse_context",
    "payload": {
      "summary": "goal: \ncompleted work: \nkey decisions: \nnext steps: \ncritical context: Explored auth module; decided token refresh strategy; next step is the login form."
    }
  }
]
```

After `default_convert_to_llm`:

```text
[Previous session compact summary]
goal: 
completed work: 
key decisions: 
next steps: 
critical context: Explored auth module; decided token refresh strategy; next step is the login form.
```

Every collapse renders the same five fixed components; plain/legacy material
lands under `critical context` and each component is bounded by the
per-component char caps in `session_ops.rs`.

### 3. Collapse into an existing session (`into_session_id`)

The existing messages remain on the active branch, then the collapse context
entries are appended after them. System prompt is the same lineage block as
case 2.

`ContextBundle.messages` before provider materialization:

```json
[
  { "role": "user", "content": "start the refactor", "timestamp": 1 },
  { "role": "assistant", "content": "beginning refactor...", "timestamp": 2 },
  {
    "type": "custom",
    "role": "collapse_context",
    "payload": {
      "summary": "goal: \ncompleted work: \nkey decisions: \nnext steps: \ncritical context: Old session covered the parser rewrite and its tests."
    }
  }
]
```

### 4. Collapse with `--adopt`

Prompt shape is unchanged from case 2. The only difference is runtime state:
active DAG runs and subagent jobs are re-homed to the new session, so the
`dag_*` tools now operate on the migrated runs while `session_graph_*` tools
can still read the collapse node.

### 5. Session with no collapse metadata

`render_lineage` returns `None`, so `compose_system_prompt` emits no
`## Session lineage` block. The context is the normal base prompt + cwd +
memory only.

### 6. Session with a custom harness introduction

When session metadata contains
`harnessIntroduction: "You are a database migration specialist."`, the first
sentence of the base prompt is replaced:

```text
<harness>
You are a database migration specialist.

Session model: ...
Exploration: ...
Graph and subagent orchestration: ...
</harness>

<tools>
- Files: edit, read, write
- Execution: bash
- Context & search: grep, outline
</tools>

<environment>
Current working directory: /home/user/project
</environment>
```

The rest of the behavioral instructions stay unchanged. To customize the
introduction, pass the metadata key at session creation or through
`update_metadata`.