o7 0.1.1

O7 workflow DSL runner
Documentation
# Q&A File Protocol

This document is the single source of truth for the question/answer file format used by the o7 workflow engine.

## Overview

During workflow execution, an agent harness (e.g., `claude-code`) may need to ask the user clarifying questions before proceeding. The Q&A protocol defines a file-based mechanism for agents to pose questions and receive answers without blocking the harness process itself.

## File Location

All Q&A files reside in the `qa/` subdirectory of the per-run state directory:

```
<run-state-dir>/qa/
  q-out-001.json      # questions from agent, batch 1
  q-answers-001.json  # user answers to batch 1
  q-out-002.json      # questions from agent, batch 2
  q-answers-002.json  # user answers to batch 2
  ...
```

The run state directory is provided to harnesses via the `RUN_STATE_DIR` environment variable (e.g., `.7/runs/<run-id>/`).

## Sequence Numbers

- Sequence numbers are **3-digit zero-padded integers** in filenames (e.g., `001`, `002`, `042`).
- The JSON `seq` field contains the **plain integer** value (e.g., `1`, `2`, `42`).
- Sequences start at **001** / `1`.
- When parsing sequence numbers from filenames in bash scripts, always force decimal interpretation to avoid the bash octal bug with zero-padded numbers: `$((10#$seq_str))`.

## `q-out-NNN.json` — Agent Question Output

Written by the agent harness when it needs information from the user.

### Schema

```json
{
  "seq": 1,
  "questions": [
    {
      "id": "string (unique within this batch)",
      "type": "choose-one | choose-many | free-write | yes-no",
      "prompt": "string (the question text shown to the user)",
      "preview": {
        "type": "markdown | ascii",
        "content": "string (optional rendered preview content)"
      },
      "options": ["string", "..."]
    }
  ]
}
```

### Question Types

| Type          | Description                                               | `options` required? |
|---------------|-----------------------------------------------------------|---------------------|
| `choose-one`  | User selects exactly one option from the list             | Yes                 |
| `choose-many` | User selects one or more options from the list            | Yes                 |
| `free-write`  | User types a free-form text answer                        | No                  |
| `yes-no`      | User answers yes or no (binary choice)                    | No                  |

### Fields

- **`seq`** *(integer, required)*: The sequence number for this batch of questions. Must match the NNN in the filename.
- **`questions`** *(array, required)*: One or more question objects. Must be non-empty.
- **`id`** *(string, required)*: Unique identifier for the question within this batch. Used to correlate answers.
- **`type`** *(string, required)*: One of the question types listed above.
- **`prompt`** *(string, required)*: The question text displayed to the user.
- **`options`** *(array of strings, conditional)*: Required for `choose-one` and `choose-many` types. Must be omitted or empty for `free-write` and `yes-no`.
- **`preview`** *(object, optional)*: An optional preview block to display before the question.
  - **`type`**: `"markdown"` or `"ascii"`.
  - **`content`**: The preview content string.

## `q-answers-NNN.json` — User Answer Input

Written by the TUI (or another answer provider) once the user has answered all questions in the corresponding `q-out-NNN.json` batch. The original questions are echoed back for traceability.

### Schema

```json
{
  "seq": 1,
  "answers": [
    {
      "id": "string (matches question id)",
      "type": "choose-one | choose-many | free-write | yes-no",
      "prompt": "string (echoed from the original question)",
      "options": ["string", "..."],
      "answer": "string | [\"string\", ...] | true | false"
    }
  ],
  "questions": [
    { "...": "original question object echoed from q-out-NNN.json" }
  ]
}
```

### Fields

- **`seq`** *(integer, required)*: Must match the `seq` of the corresponding `q-out-NNN.json`.
- **`answers`** *(array, required)*: One entry per question in the batch. Each answer echoes back the original question fields for self-contained traceability.
  - **`id`** *(string)*: Matches the `id` from the question.
  - **`type`** *(string)*: Echoed from the original question.
  - **`prompt`** *(string)*: Echoed from the original question.
  - **`options`** *(array of strings, conditional)*: Echoed from the original question if present.
  - **`answer`**: The user's response. Type depends on question type:
    - `choose-one`: a single `string` matching one option.
    - `choose-many`: an array of strings, each matching an option.
    - `free-write`: a `string`.
    - `yes-no`: `true` or `false`.
- **`questions`** *(array, required)*: The original question objects from `q-out-NNN.json`, echoed verbatim for traceability and context.

## Detection Mechanism

The TUI watches the `<run-state-dir>/qa/` directory for new `q-out-NNN.json` files using filesystem events (`fs.watch` or `inotify`). A polling fallback (e.g., every 500ms) is used when fs watch is unavailable or unreliable.

## Queuing Behavior

Multiple `q-out-NNN.json` files may accumulate if the agent writes them faster than the user answers. The TUI processes them **in ascending sequence order**. It will not present batch N+1 to the user until `q-answers-N.json` has been written.

## Example

### `qa/q-out-001.json`

```json
{
  "seq": 1,
  "questions": [
    {
      "id": "output-format",
      "type": "choose-one",
      "prompt": "What output format should the workflow produce?",
      "options": ["JSON", "CSV", "plain text"]
    },
    {
      "id": "description",
      "type": "free-write",
      "prompt": "Describe the workflow you want to generate in a few sentences."
    }
  ]
}
```

### `qa/q-answers-001.json`

```json
{
  "seq": 1,
  "answers": [
    {
      "id": "output-format",
      "type": "choose-one",
      "prompt": "What output format should the workflow produce?",
      "options": ["JSON", "CSV", "plain text"],
      "answer": "JSON"
    },
    {
      "id": "description",
      "type": "free-write",
      "prompt": "Describe the workflow you want to generate in a few sentences.",
      "answer": "A workflow that fetches data from an API and stores results."
    }
  ],
  "questions": [
    {
      "id": "output-format",
      "type": "choose-one",
      "prompt": "What output format should the workflow produce?",
      "options": ["JSON", "CSV", "plain text"]
    },
    {
      "id": "description",
      "type": "free-write",
      "prompt": "Describe the workflow you want to generate in a few sentences."
    }
  ]
}
```