# INTERACTIVE_RUNNER.md

`./grownet.sh --lang python --interactive` starts a live keyboard-driven GrowNet probing session.

## Purpose

Interactive mode keeps a persistent GrowNet instance alive so you can press keys, send one input tick at a time, and watch the network adapt or grow from a stable initial scaffold.

Mental model:

- initial scaffold from a built-in profile or config file
- live key input applied one tick at a time
- normal GrowNet slot, neuron, and layer growth still remains active

Reset rebuilds the original scaffold from the same profile/config and returns to tick `0`.

## Scope

This PR implements interactive mode in Python first.

- `--lang python --interactive` is implemented
- `--lang java --interactive` returns a clear not-implemented message
- Mojo and C++ interactive mode are not implemented here

## Flags

- `--interactive`
- `--profile single_scalar|dual_scalar|growth_probe`
- `--config path/to/experiment.json`
- `--normalize-inputs normalized|raw`
- `--interactive-output compact|verbose|jsonl`
- `--interactive-trace on|off`

Defaults for `./grownet.sh --lang python --interactive`:

- profile: `single_scalar`
- normalize inputs: `normalized`
- output: `compact`
- trace: `off`

## Built-in Profiles

### `single_scalar`

- one scalar input port: `a`
- simple scalar scaffold for immediate probing
- good default for learning slot selection and downstream delivery behavior

### `dual_scalar`

- two scalar input ports: `a` and `b`
- one key press triggers one multi-port tick
- if one port changes, the other port keeps its previous value

### `growth_probe`

- one scalar input port: `a`
- a small scaffold biased toward visible growth
- useful for repeated novelty experiments and reset/replay

## Config Support

`--config` loads a JSON file that defines the initial scaffold and interactive defaults.

Interactive mode reuses the same scaffold-oriented config fields documented in `docs/EXPERIMENT_RUNNER.md`, then layers the keyboard-specific interactive defaults on top.

Example:

```json
{
  "name": "dual_scalar_probe",
  "interactive": {
    "output": "compact",
    "trace": false,
    "normalize_inputs": "normalized"
  },
  "input_space": {
    "rank": 1,
    "ports": [
      {"name": "a"},
      {"name": "b"}
    ]
  },
  "network": {
    "regions": [
      {
        "name": "main",
        "layers": [
          {
            "excitatory_count": 20,
            "inhibitory_count": 4,
            "modulatory_count": 2
          }
        ]
      }
    ]
  }
}
```

Current behavior:

- the config defines the starting scaffold only
- if no `input_bindings` are provided, all input ports bind to layer `0`
- if no `connections` are provided and a region has multiple layers, consecutive layers auto-connect with probability `1.0`
- keyboard-driven interactive configs are currently meaningful for rank-1 scalar input spaces; shaped file-driven experiments belong to the non-interactive experiment runner path
- if the scaffold/config enables focus, interactive summaries surface the current focus policy, active focus/anchor summary, and remembered anchor count

## Input Mapping

### Normalized mode

- `0 -> 0.0`
- `1 -> 0.1`
- `2 -> 0.2`
- ...
- `9 -> 0.9`

### Raw mode

- `0 -> 0.0`
- `1 -> 1.0`
- `2 -> 2.0`
- ...
- `9 -> 9.0`

## Dual-input Mapping

For `dual_scalar`:

- top-row digits update port `a`
- when the platform exposes distinct keypad tokens, keypad digits update port `b`
- fallback mapping for port `b`: `Q W E R T Y U I O P -> 1 2 3 4 5 6 7 8 9 0`

Example:

- current state: `a=0.2`, `b=0.7`
- press top-row `5`
- next tick uses `a=0.5`, `b=0.7`

- press fallback `E`
- next tick uses `a=0.5`, `b=0.3`

## Control Keys

- `space` = run one tick again with the current input state
- `r` = reset the network to the original scaffold and zeroed inputs
- `s` = print a current summary without advancing the tick
- `t` = toggle compact/verbose summary output
- `c` = reprint the startup panel
- `h` = print help
- `q` = quit

## Output Modes

### `compact`

One concise line per interactive tick summary.

If focus metadata is available, compact mode appends fields such as `policy=...`, `focus=...`, `anchor=...`, and `anchor_count=...`.

### `verbose`

Multi-line summary with key, port, inputs, metrics, and growth deltas.

When focus metadata is available, verbose mode includes a dedicated focus summary line.

### `jsonl`

One JSON object per summary event, for example:

```json
{"event":"interactive.tick","tick":12,"profile":"dual_scalar","updated_port":"a","input_a":0.4,"input_b":0.7,"fired":true,"delivered_events":1,"total_slots":5,"layer_count":1,"region_count":1}
```

If focus metadata is available, JSONL summaries also include fields such as `focus_policy`, `focus_point`, `focus_value`, `anchor_point`, `anchor_value`, `anchor_count`, and `focus_candidate_count`.

## Trace Interaction

- `--interactive-trace off` keeps interactive summaries only
- `--interactive-trace on` emits full trace events for each tick before the interactive summary
- text summary modes use text trace lines
- `jsonl` summary mode uses JSONL trace lines

## Example Commands

```bash
./grownet.sh --lang python --interactive
./grownet.sh --lang python --interactive --profile dual_scalar
./grownet.sh --lang python --interactive --profile growth_probe --interactive-output verbose
./grownet.sh --lang python --interactive --config configs/interactive_probe.json --normalize-inputs raw
./grownet.sh --lang python --interactive --profile dual_scalar --interactive-output jsonl --interactive-trace on
```

## Notes

- Interactive mode uses the real Python runtime rather than a toy model.
- Reset rebuilds the original scaffold but keeps the current CLI-selected output and trace settings.
- Java interactive mode is intentionally not implemented in this PR to keep the first implementation Pythonic and easy for Mojo to follow later.
