Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ while (pos < slice.len) { ... }
The `<= len` pattern is only correct when `pos` represents a position *after* processing (e.g., `slice[0..pos]` as a "processed so far" marker).

## Build and Test (required after every task)
- Run `zig build` and `zig build test` (or `just ci` when appropriate) once the task is complete.
- Run `zig build`, `zig build test`, and `just lint` (or `just ci` when appropriate) once the task is complete.
- Report the results in your summary; if you must skip tests, state the reason explicitly.

## Documentation Hygiene (REQUIRED)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Common settings include font family, theme colors, and grid font scale. The grid

## Documentation

* [`docs/ai-integration.md`](docs/ai-integration.md): set up Claude Code, Codex, and Gemini CLI hooks for status notifications.
* [`docs/ai-integration.md`](docs/ai-integration.md): set up Claude Code, Codex, and Gemini CLI hooks for status notifications (includes `architect notify`, `architect hook ...`, and timestamped backups).
* [`docs/architecture.md`](docs/architecture.md): architecture overview and system boundaries.
* [`docs/configuration.md`](docs/configuration.md): detailed configuration reference for `config.toml` and `persistence.toml`.
* [`docs/development.md`](docs/development.md): build, test, and release process.
Expand Down
46 changes: 40 additions & 6 deletions docs/ai-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,37 @@ Examples:
{"session": 0, "state": "done"}
```

## Built-in Command (inside Architect terminals)

Architect injects a small `architect` command into each shell's `PATH`. It reads the
session id and socket path from the environment, so hooks can simply call:

```bash
architect notify start
architect notify awaiting_approval
architect notify done
```

If your hook runs outside an Architect terminal, use the Python helper scripts below.
Replace `architect notify ...` in the examples with `python3 ~/.<tool>/architect_notify.py ...` when using those scripts.

## Hook Installer

From inside an Architect terminal, you can install hooks automatically:

```bash
architect hook claude
architect hook codex
architect hook gemini
```

If you upgrade Architect, restart existing terminals so the bundled `architect` script refreshes.
The installer writes timestamped backups before updating configs (for example:
`settings.json.architect.bak.20260127T153045Z`).

## Claude Code Hooks

1. Copy the helper script:
1. (Optional) Copy the helper script if the hook runs outside Architect:
```bash
cp scripts/architect_notify.py ~/.claude/architect_notify.py
chmod +x ~/.claude/architect_notify.py
Expand All @@ -32,7 +60,7 @@ Examples:
"hooks": [
{
"type": "command",
"command": "python3 ~/.claude/architect_notify.py done || true"
"command": "architect notify done || true"
}
]
}
Expand All @@ -42,7 +70,7 @@ Examples:
"hooks": [
{
"type": "command",
"command": "python3 ~/.claude/architect_notify.py awaiting_approval || true"
"command": "architect notify awaiting_approval || true"
}
]
}
Expand All @@ -53,20 +81,26 @@ Examples:

## Codex Hooks

1. Copy the helper script:
1. (Optional) Copy the helper script if the hook runs outside Architect:
```bash
cp scripts/architect_notify.py ~/.codex/architect_notify.py
chmod +x ~/.codex/architect_notify.py
```

2. Add the `notify` setting to `~/.codex/config.toml`:
```toml
notify = ["python3", "/Users/your-username/.codex/architect_notify.py"]
notify = ["architect", "notify"]
```

If you already have `notify` configured, `architect hook codex` overwrites it,
prints a warning, and prints the backup file name.

## Gemini CLI Hooks

1. Copy the notification scripts:
Gemini hooks must emit JSON to stdout, so keep using the wrapper script even inside
Architect terminals (it can call `architect notify` under the hood).

1. Copy the notification scripts (the `architect hook gemini` installer assumes they exist):
```bash
cp scripts/architect_notify.py ~/.gemini/architect_notify.py
cp scripts/architect_hook_gemini.py ~/.gemini/architect_hook.py
Expand Down
4 changes: 4 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ Protocol: Single-line JSON
{"session": 0, "state": "start"}
```

Each shell also gets a small `architect` command in `PATH` that wraps this protocol
and reads `ARCHITECT_SESSION_ID`/`ARCHITECT_NOTIFY_SOCK` (for example,
`architect notify done`).

A background thread (`notify.zig`) accepts connections, parses messages, and pushes to a thread-safe `NotificationQueue`. Main loop drains queue each frame.

## First Frame Guard Pattern
Expand Down
27 changes: 18 additions & 9 deletions scripts/architect_hook_gemini.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
Gemini CLI hook wrapper for Architect notifications.

Gemini hooks receive JSON via stdin and must output JSON to stdout.
This wrapper consumes stdin, calls architect_notify.py, and returns valid JSON.
This wrapper consumes stdin, calls Architect notify, and returns valid JSON.
"""

import json
import os
import sys
import shutil
import subprocess
import sys


def main() -> int:
Expand All @@ -29,13 +30,21 @@ def main() -> int:

state = sys.argv[1]

# Call architect_notify.py script
script_path = os.path.join(os.path.dirname(__file__), "architect_notify.py")
subprocess.run(
["python3", script_path, state],
check=False,
capture_output=True,
)
# Prefer built-in architect command when available, fall back to script.
architect_cmd = shutil.which("architect")
if architect_cmd:
subprocess.run(
[architect_cmd, "notify", state],
check=False,
capture_output=True,
)
else:
script_path = os.path.join(os.path.dirname(__file__), "architect_notify.py")
subprocess.run(
["python3", script_path, state],
check=False,
capture_output=True,
)

# Return success JSON to Gemini (required)
print(json.dumps({"decision": "allow"}))
Expand Down
Loading