ctlrm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. ctlrm-0.1.0/.agents/skills/ctlrm/SKILL.md +29 -0
  2. ctlrm-0.1.0/.agents/skills/ctlrm/references/protocol.md +68 -0
  3. ctlrm-0.1.0/.github/workflows/ci.yml +121 -0
  4. ctlrm-0.1.0/.github/workflows/release.yml +33 -0
  5. ctlrm-0.1.0/.gitignore +19 -0
  6. ctlrm-0.1.0/.pre-commit-config.yaml +13 -0
  7. ctlrm-0.1.0/AGENTS.md +12 -0
  8. ctlrm-0.1.0/PKG-INFO +82 -0
  9. ctlrm-0.1.0/docs/evidence/csv-brief-recovery-2026-09-06.json +203 -0
  10. ctlrm-0.1.0/docs/evidence/managed-codex-recovery-2026-09-05.json +1 -0
  11. ctlrm-0.1.0/docs/evidence/managed-interrupted-recovery-2026-09-05.json +1 -0
  12. ctlrm-0.1.0/docs/evidence/managed-native-recovery-2026-09-05.json +1 -0
  13. ctlrm-0.1.0/docs/evidence/mixed-workflow-2026-09-05.json +1 -0
  14. ctlrm-0.1.0/docs/evidence/native-delivery-retry-2026-09-05.json +1 -0
  15. ctlrm-0.1.0/docs/evidence/pocket-tasks-workflow-2026-09-06.json +85 -0
  16. ctlrm-0.1.0/docs/evidence/project-archive-2026-09-05.json +79 -0
  17. ctlrm-0.1.0/docs/evidence/provider-recovery-2026-09-05.json +45 -0
  18. ctlrm-0.1.0/docs/evidence/provider-recovery-streamed-2026-09-05.json +59 -0
  19. ctlrm-0.1.0/docs/evidence/readme.md +11 -0
  20. ctlrm-0.1.0/docs/evidence/suite-timing-2026-09-06.json +283 -0
  21. ctlrm-0.1.0/docs/evidence/web-workbench-2026-09-06.json +69 -0
  22. ctlrm-0.1.0/docs/managed-sessions.md +31 -0
  23. ctlrm-0.1.0/docs/projects.md +47 -0
  24. ctlrm-0.1.0/docs/provider-session-recovery.md +80 -0
  25. ctlrm-0.1.0/docs/releases.md +31 -0
  26. ctlrm-0.1.0/docs/superpowers/plans/2026-06-20-tui-agent-orchestrator.md +1142 -0
  27. ctlrm-0.1.0/docs/superpowers/plans/2026-09-05-background-agent-workflows.md +242 -0
  28. ctlrm-0.1.0/docs/superpowers/plans/2026-09-05-project-jobs.md +14 -0
  29. ctlrm-0.1.0/docs/superpowers/specs/2026-06-20-tui-agent-orchestrator-design.md +350 -0
  30. ctlrm-0.1.0/docs/web-workbench.md +54 -0
  31. ctlrm-0.1.0/docs/workflows.md +41 -0
  32. ctlrm-0.1.0/frontend/build.mjs +14 -0
  33. ctlrm-0.1.0/frontend/package-lock.json +94 -0
  34. ctlrm-0.1.0/frontend/package.json +18 -0
  35. ctlrm-0.1.0/frontend/playwright.config.mjs +17 -0
  36. ctlrm-0.1.0/pyproject.toml +51 -0
  37. ctlrm-0.1.0/readme.md +64 -0
  38. ctlrm-0.1.0/src/ctlrm/__init__.py +3 -0
  39. ctlrm-0.1.0/src/ctlrm/__main__.py +307 -0
  40. ctlrm-0.1.0/src/ctlrm/communication/__init__.py +1 -0
  41. ctlrm-0.1.0/src/ctlrm/communication/terminal.py +292 -0
  42. ctlrm-0.1.0/src/ctlrm/managed/__init__.py +1 -0
  43. ctlrm-0.1.0/src/ctlrm/managed/archive.py +269 -0
  44. ctlrm-0.1.0/src/ctlrm/managed/area.py +201 -0
  45. ctlrm-0.1.0/src/ctlrm/managed/artifacts.py +164 -0
  46. ctlrm-0.1.0/src/ctlrm/managed/cli.py +276 -0
  47. ctlrm-0.1.0/src/ctlrm/managed/codex_host.py +187 -0
  48. ctlrm-0.1.0/src/ctlrm/managed/commits.py +178 -0
  49. ctlrm-0.1.0/src/ctlrm/managed/host.py +58 -0
  50. ctlrm-0.1.0/src/ctlrm/managed/project_cli.py +162 -0
  51. ctlrm-0.1.0/src/ctlrm/managed/projects.py +494 -0
  52. ctlrm-0.1.0/src/ctlrm/managed/providers.py +157 -0
  53. ctlrm-0.1.0/src/ctlrm/managed/sessions.py +691 -0
  54. ctlrm-0.1.0/src/ctlrm/managed/storage.py +232 -0
  55. ctlrm-0.1.0/src/ctlrm/managed/supervisor.py +133 -0
  56. ctlrm-0.1.0/src/ctlrm/managed/workflow_cli.py +161 -0
  57. ctlrm-0.1.0/src/ctlrm/managed/workflows.py +696 -0
  58. ctlrm-0.1.0/src/ctlrm/runtime/__init__.py +1 -0
  59. ctlrm-0.1.0/src/ctlrm/runtime/documents.py +60 -0
  60. ctlrm-0.1.0/src/ctlrm/runtime/filesystem.py +65 -0
  61. ctlrm-0.1.0/src/ctlrm/runtime/location.py +36 -0
  62. ctlrm-0.1.0/src/ctlrm/runtime/manifest.py +125 -0
  63. ctlrm-0.1.0/src/ctlrm/runtime/messages.py +69 -0
  64. ctlrm-0.1.0/src/ctlrm/runtime/participants.py +89 -0
  65. ctlrm-0.1.0/src/ctlrm/runtime/paths.py +17 -0
  66. ctlrm-0.1.0/src/ctlrm/runtime/projects.py +113 -0
  67. ctlrm-0.1.0/src/ctlrm/runtime/room.py +265 -0
  68. ctlrm-0.1.0/src/ctlrm/runtime/workflows.py +230 -0
  69. ctlrm-0.1.0/src/ctlrm/scheduler.py +23 -0
  70. ctlrm-0.1.0/src/ctlrm/version.py +11 -0
  71. ctlrm-0.1.0/src/ctlrm/web/__init__.py +1 -0
  72. ctlrm-0.1.0/src/ctlrm/web/api.py +272 -0
  73. ctlrm-0.1.0/src/ctlrm/web/app.py +74 -0
  74. ctlrm-0.1.0/src/ctlrm/web/service.py +354 -0
  75. ctlrm-0.1.0/src/ctlrm/web/static/app.css +1220 -0
  76. ctlrm-0.1.0/src/ctlrm/web/static/app.js +1319 -0
  77. ctlrm-0.1.0/src/ctlrm/web/static/index.html +129 -0
  78. ctlrm-0.1.0/src/ctlrm/web/static/vendor/addon-fit.LICENSE +19 -0
  79. ctlrm-0.1.0/src/ctlrm/web/static/vendor/addon-fit.js +2 -0
  80. ctlrm-0.1.0/src/ctlrm/web/static/vendor/xterm.LICENSE +21 -0
  81. ctlrm-0.1.0/src/ctlrm/web/static/vendor/xterm.css +285 -0
  82. ctlrm-0.1.0/src/ctlrm/web/static/vendor/xterm.js +2 -0
  83. ctlrm-0.1.0/src/ctlrm/web/templates/implement-review.yaml +44 -0
  84. ctlrm-0.1.0/src/ctlrm/web/templates/ship.yaml +81 -0
  85. ctlrm-0.1.0/src/ctlrm/web/templates/single-agent.yaml +21 -0
  86. ctlrm-0.1.0/src/ctlrm/web/terminal.py +164 -0
  87. ctlrm-0.1.0/tests/communication/test_terminal.py +288 -0
  88. ctlrm-0.1.0/tests/managed/conftest.py +140 -0
  89. ctlrm-0.1.0/tests/managed/test_archive.py +540 -0
  90. ctlrm-0.1.0/tests/managed/test_area.py +91 -0
  91. ctlrm-0.1.0/tests/managed/test_artifacts.py +77 -0
  92. ctlrm-0.1.0/tests/managed/test_cli.py +225 -0
  93. ctlrm-0.1.0/tests/managed/test_codex_host.py +133 -0
  94. ctlrm-0.1.0/tests/managed/test_commits.py +171 -0
  95. ctlrm-0.1.0/tests/managed/test_dispatch.py +109 -0
  96. ctlrm-0.1.0/tests/managed/test_host.py +122 -0
  97. ctlrm-0.1.0/tests/managed/test_interactions.py +252 -0
  98. ctlrm-0.1.0/tests/managed/test_projects.py +441 -0
  99. ctlrm-0.1.0/tests/managed/test_providers.py +134 -0
  100. ctlrm-0.1.0/tests/managed/test_sessions.py +379 -0
  101. ctlrm-0.1.0/tests/managed/test_specialists.py +382 -0
  102. ctlrm-0.1.0/tests/managed/test_storage.py +121 -0
  103. ctlrm-0.1.0/tests/managed/test_supervisor.py +111 -0
  104. ctlrm-0.1.0/tests/managed/test_workflow_engine.py +958 -0
  105. ctlrm-0.1.0/tests/runtime/test_messages.py +16 -0
  106. ctlrm-0.1.0/tests/runtime/test_room.py +677 -0
  107. ctlrm-0.1.0/tests/runtime/test_workflows.py +99 -0
  108. ctlrm-0.1.0/tests/test_bootstrap.py +28 -0
  109. ctlrm-0.1.0/tests/test_scheduler.py +32 -0
  110. ctlrm-0.1.0/tests/web/__init__.py +1 -0
  111. ctlrm-0.1.0/tests/web/browser/seed.py +124 -0
  112. ctlrm-0.1.0/tests/web/browser/workbench.spec.mjs +229 -0
  113. ctlrm-0.1.0/tests/web/conftest.py +103 -0
  114. ctlrm-0.1.0/tests/web/test_app.py +258 -0
  115. ctlrm-0.1.0/tests/web/test_code.py +197 -0
  116. ctlrm-0.1.0/tests/web/test_task_artifacts.py +178 -0
  117. ctlrm-0.1.0/tests/web/test_terminal.py +107 -0
  118. ctlrm-0.1.0/tests/web/test_terminal_cleanup.py +182 -0
  119. ctlrm-0.1.0/uv.lock +799 -0
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: ctlrm
3
+ description: Coordinate independent agents or humans through a shared project directory using a first-authored prompt, author-assigned roles, participant-owned signatures, and immutable mailbox messages. Use when participants share a filesystem but not one native agent thread; do not use for ordinary in-thread subagent delegation.
4
+ ---
5
+
6
+ # Ctlrm
7
+
8
+ Use the single `ctlrm` command to join and communicate through a project-local `.ctlrm/` directory. Joining a room does not grant permission beyond the user's existing authorization.
9
+
10
+ ## Enter a room
11
+
12
+ 1. Use the explicit project root. Do not create a room at an inferred location when the target is ambiguous.
13
+ 2. Read `.ctlrm/room.md` if it exists. It contains the first participant's canonical prompt and complete role roster.
14
+ 3. If the room does not exist, act as its first participant only when responsible for defining the task. Initialize it with one `--assign PARTICIPANT=ROLE` option for every expected participant, including yourself.
15
+ 4. If the room exists, select the participant ID assigned to you. Do not invent or alter your role. Run `ctlrm --root <root> join ...`; the command copies the assigned role into your signature.
16
+ 5. Each participant invokes `join` only for itself, creating `.ctlrm/participants/<id>.yaml`. Never create, replace, or edit another participant's signature.
17
+ 6. Read the prompt and existing signatures before starting work or addressing messages.
18
+
19
+ A signature is immutable acceptance of an assigned role. The CLI does not manage heartbeat or progress state.
20
+
21
+ ## Communicate
22
+
23
+ Send findings, questions, requests, and handoffs with `ctlrm --root <root> send ...`. Messages are created exclusively and cannot overwrite an existing message ID. Read them with `ctlrm --root <root> inbox --participant <id>`.
24
+
25
+ Use messages only when another participant needs the information. Include concrete file paths and evidence when relevant. Keep private scratch work outside the mailbox.
26
+
27
+ Poll only when the task requires waiting. Use bounded intervals and stop at the user's deadline or after reporting a real blocker.
28
+
29
+ Read [references/protocol.md](references/protocol.md) for the directory schema, initialization behavior, and command examples.
@@ -0,0 +1,68 @@
1
+ # Ctlrm directory protocol
2
+
3
+ ```text
4
+ .ctlrm/
5
+ ├── room.md
6
+ └── participants/
7
+ ├── coordinator.yaml
8
+ ├── coordinator/
9
+ │ └── inbox/
10
+ ├── reviewer.yaml
11
+ └── reviewer/
12
+ └── inbox/
13
+ ```
14
+
15
+ ## Room definition
16
+
17
+ `room.md` is an immutable Markdown document with YAML front matter. The body is the first participant's prompt. The front matter records `protocol_version`, a room `id`, the `author`, `created_at`, and the complete list of participant-to-role `assignments`.
18
+
19
+ The author must assign itself a role. Participant IDs must be unique, and every participant must have exactly one role. Only assigned participant IDs can join.
20
+
21
+ ```bash
22
+ ctlrm --root /path/to/project init \
23
+ --id coordinator \
24
+ --name Coordinator \
25
+ --provider codex \
26
+ --assign coordinator=coordinate \
27
+ --assign reviewer=review \
28
+ --prompt-file /path/to/prompt.md
29
+ ```
30
+
31
+ Room creation is exclusive. A repeated `init` by the same author with the same prompt and assignments repairs a missing author signature and otherwise leaves the room unchanged. A different author, prompt, or roster is a conflict.
32
+
33
+ ## Participant signatures
34
+
35
+ Each participant accepts its preassigned role by invoking:
36
+
37
+ ```bash
38
+ ctlrm --root /path/to/project join \
39
+ --id reviewer \
40
+ --name Reviewer \
41
+ --provider claude \
42
+ --capability code-review
43
+ ```
44
+
45
+ `join` has no role option. It reads the role from `room.md` and creates `participants/<id>.yaml` plus that participant's inbox. A signature contains `protocol_version`, `room_id`, `id`, `name`, `role`, `kind`, optional `provider`, `joined_at`, and optional `capabilities`.
46
+
47
+ ## Messaging
48
+
49
+ ```bash
50
+ ctlrm --root /path/to/project send \
51
+ --from coordinator \
52
+ --to reviewer \
53
+ --kind review_request \
54
+ --title "Review the implementation" \
55
+ --file src/ctlrm/runtime/room.py \
56
+ --body "Check role enforcement and recovery."
57
+
58
+ ctlrm --root /path/to/project inbox --participant reviewer
59
+ ctlrm --root /path/to/project participants
60
+ ```
61
+
62
+ Both endpoints must have valid signatures bound to the current room and their assigned roles. Duplicate message IDs return conflict exit code 3. Validation returns 2, missing files return 4, and storage failures return 5.
63
+
64
+ ## Ownership and storage
65
+
66
+ The CLI exclusively creates `room.md`, signatures, and messages. By convention, the first participant authors `room.md`, each participant authors only its own signature, and each declared sender authors its messages. These rules are cooperative rather than authenticated; any process with directory write access can unlink or forge files.
67
+
68
+ Ctlrm creates files with mode `0660` and directories with mode `2770`. Participants running as different users must share the directory's Unix group. Exclusive creation requires a POSIX-style filesystem supporting hard links and directory `fsync`; ctlrm reports a storage error rather than weakening the no-overwrite guarantee.
@@ -0,0 +1,121 @@
1
+ name: checks
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ workflow_dispatch:
7
+ workflow_call:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ timeout-minutes: 10
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0
20
+ persist-credentials: false
21
+ - uses: astral-sh/setup-uv@v6
22
+ with:
23
+ python-version: '3.11'
24
+ - name: Validate release tag
25
+ if: github.event_name == 'release'
26
+ env:
27
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
28
+ run: |
29
+ [[ "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?$ ]]
30
+ git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main \
31
+ "+refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG"
32
+ git merge-base --is-ancestor HEAD origin/main
33
+ test "$(git rev-parse "refs/tags/$RELEASE_TAG^{commit}")" = "$(git rev-parse HEAD)"
34
+ - name: Build sdist, then wheel from sdist
35
+ run: uv build
36
+ - run: uvx twine==7.0.0 check --strict dist/*
37
+ - name: Verify release package version
38
+ if: github.event_name == 'release'
39
+ env:
40
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
41
+ run: |
42
+ uv run --no-project python - <<'PYTHON'
43
+ import email
44
+ import os
45
+ import pathlib
46
+ import zipfile
47
+
48
+ wheel, = pathlib.Path("dist").glob("*.whl")
49
+ with zipfile.ZipFile(wheel) as archive:
50
+ metadata_path, = (name for name in archive.namelist() if name.endswith(".dist-info/METADATA"))
51
+ metadata = email.message_from_bytes(archive.read(metadata_path))
52
+ if metadata["Name"] != "ctlrm" or "v" + metadata["Version"] != os.environ["RELEASE_TAG"]:
53
+ raise SystemExit("Package name/version does not match the release tag")
54
+ PYTHON
55
+ - uses: actions/upload-artifact@v4
56
+ with:
57
+ name: python-distributions
58
+ path: dist/*
59
+ if-no-files-found: error
60
+ retention-days: 7
61
+
62
+ test:
63
+ needs: build
64
+ runs-on: ubuntu-latest
65
+ timeout-minutes: 20
66
+ strategy:
67
+ fail-fast: false
68
+ matrix:
69
+ python: ['3.11', '3.14']
70
+ steps:
71
+ - uses: actions/checkout@v4
72
+ with:
73
+ fetch-depth: 0
74
+ persist-credentials: false
75
+ - uses: astral-sh/setup-uv@v6
76
+ with:
77
+ python-version: ${{ matrix.python }}
78
+ - uses: actions/setup-node@v4
79
+ with:
80
+ node-version: '24'
81
+ cache: npm
82
+ cache-dependency-path: frontend/package-lock.json
83
+ - name: Install tmux for terminal integration tests
84
+ run: sudo apt-get update && sudo apt-get install -y tmux
85
+ - run: uv sync --locked
86
+ - run: npm --prefix frontend ci
87
+ - run: npm --prefix frontend run check
88
+ - name: Verify bundled terminal assets are reproducible
89
+ run: |
90
+ npm --prefix frontend run build
91
+ git diff --exit-code -- src/ctlrm/web/static/vendor
92
+ - name: Install browser for workbench acceptance
93
+ run: npm --prefix frontend exec -- playwright install --with-deps chromium --only-shell
94
+ - run: uv run ruff check .
95
+ - run: uv run ruff format --check .
96
+ - run: uv run pytest --cov ctlrm --cov-report term-missing --cov-report xml:test-results/coverage.xml --durations=25 --junitxml=test-results/python.xml
97
+ - uses: actions/download-artifact@v4
98
+ with:
99
+ name: python-distributions
100
+ path: dist
101
+ - name: Test installed wheel outside source tree
102
+ run: |
103
+ uv venv --python '${{ matrix.python }}' /tmp/ctlrm-wheel
104
+ uv pip install --python /tmp/ctlrm-wheel/bin/python dist/*.whl
105
+ cd /tmp
106
+ /tmp/ctlrm-wheel/bin/ctlrm --help
107
+ - name: Test installed workbench in Chromium
108
+ env:
109
+ CTLRM_BROWSER_PYTHON: /tmp/ctlrm-wheel/bin/python
110
+ CTLRM_BROWSER_REQUIRE_WHEEL: '1'
111
+ run: npm --prefix frontend run test:browser
112
+ - name: Preserve test results
113
+ if: always()
114
+ uses: actions/upload-artifact@v4
115
+ with:
116
+ name: test-results-python-${{ matrix.python }}
117
+ path: |
118
+ test-results/
119
+ frontend/test-results/
120
+ if-no-files-found: ignore
121
+ retention-days: 7
@@ -0,0 +1,33 @@
1
+ name: release
2
+ on:
3
+ release:
4
+ types: [published]
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ concurrency:
10
+ group: pypi-${{ github.event.release.tag_name }}
11
+ cancel-in-progress: false
12
+
13
+ jobs:
14
+ checks:
15
+ uses: ./.github/workflows/ci.yml
16
+
17
+ publish:
18
+ needs: checks
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 10
21
+ environment:
22
+ name: pypi
23
+ url: https://pypi.org/project/ctlrm/
24
+ permissions:
25
+ contents: read
26
+ id-token: write
27
+ steps:
28
+ - uses: actions/download-artifact@v4
29
+ with:
30
+ name: python-distributions
31
+ path: dist
32
+ - name: Publish tested distributions to PyPI
33
+ uses: pypa/gh-action-pypi-publish@release/v1
ctlrm-0.1.0/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ .ctlrm/
2
+ .superpowers/
3
+ .venv/
4
+ .venv-*/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ __pycache__/
8
+ *.py[cod]
9
+ # Local coordination data, including a .scratch symlink.
10
+ .scratch
11
+ .coverage*
12
+ htmlcov/
13
+ dist/
14
+
15
+ frontend/node_modules/
16
+
17
+ frontend/test-results/
18
+ frontend/playwright-report/
19
+ /test-results/
@@ -0,0 +1,13 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff-check
5
+ name: ruff check
6
+ entry: uv run ruff check
7
+ language: system
8
+ types_or: [python, pyi]
9
+ - id: ruff-format
10
+ name: ruff format
11
+ entry: uv run ruff format --check
12
+ language: system
13
+ types_or: [python, pyi]
ctlrm-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,12 @@
1
+ # Code development guidance
2
+ - Put tests under `tests/` mirroring package structure.
3
+ - Group tests in classes.
4
+ - Place fixtures as close as practical to usage (class, module, then `conftest.py`).
5
+ - Write tests that focus on boundaries, not implementation details.
6
+ - Keep test names short; put extra detail in the docstring when needed.
7
+ - Add type hints for public functions/methods.
8
+ - All functions, classes and modules must have a docstring, private code needs only something short.
9
+ - Prefer concise explanatory docstrings. Describe parameters and return values when their behavior needs clarification.
10
+ - Don't add newlines to markdown prose; let editors wrap.
11
+ - coverage by `pytest --cov ctlrm --cov-report term-missing`
12
+ - link by `uvx prek run --all-files`
ctlrm-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.5
2
+ Name: ctlrm
3
+ Version: 0.1.0
4
+ Summary: Local web workbench for orchestrating CLI agents and human workflow participants
5
+ Project-URL: Repository, https://github.com/d-chambers/ctlrm
6
+ Project-URL: Documentation, https://github.com/d-chambers/ctlrm/tree/main/docs
7
+ Project-URL: Issues, https://github.com/d-chambers/ctlrm/issues
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: anyio<5,>=4
10
+ Requires-Dist: fastapi<1,>=0.115
11
+ Requires-Dist: libtmux<0.63,>=0.62
12
+ Requires-Dist: pydantic>=2.7
13
+ Requires-Dist: pyyaml>=6.0
14
+ Requires-Dist: typer>=0.12
15
+ Requires-Dist: uvicorn<1,>=0.34
16
+ Requires-Dist: websockets<17,>=14
17
+ Description-Content-Type: text/markdown
18
+
19
+ # ctlrm
20
+
21
+ Control room coordinates CLI agents and human participants through a shared directory. The CLI manages background Codex and Claude sessions, native recovery, reusable sequential workflows, review loops, and human response steps. Projects organize improvements to a codebase; each job uses its own Git worktree and branch to execute a workflow. Standalone managed sessions are also supported. The local web workbench provides project and participant tabs, workflow graphs, human responses, artifacts, code browsing, and direct access to managed agent sessions.
22
+
23
+ ## Open the workbench
24
+
25
+ Run `uv run ctlrm serve` and open the complete loopback URL printed in the terminal. Installed packages use `ctlrm serve`. The browser uses the same central project records as the CLI; `--data PATH` selects an isolated store and `--port PORT` changes the default port 8766. The server binds only to `127.0.0.1`. Its generated access capability is carried in the initial URL fragment, removed from the address bar, and retained for that browser tab.
26
+
27
+ Create a project, add a job using a packaged workflow or custom YAML, then explicitly start it. Opening an agent terminal attaches to its existing tmux session. Interactive providers accept direct keyboard input; native Codex sessions use a conversation message composer between turns. Closing the terminal or browser leaves the agent running. Drag the sidebar divider or terminal divider, or focus a divider and use arrow keys; Full screen and Escape preserve the same terminal view. See the [web workbench guide](https://github.com/d-chambers/ctlrm/blob/main/docs/web-workbench.md) for controls and boundaries.
28
+
29
+ ## Data model
30
+
31
+ ```text
32
+ Codebase
33
+ └── Project — a goal or related goals, with an optional design document
34
+ └── Job — a deliverable, usually a PR, defined by a workflow
35
+ └── Task — a fixed, generic assignment defined in the workflow
36
+ └── Execution — one attempt, assigned to a participant and optional agent session
37
+ ```
38
+
39
+ A **workflow** is a reusable YAML template defining the task graph, task instructions, participant roles, provider/model profiles, and outcome transitions. For example, a job might run “implement the goal,” “review blast radius,” and “review performance.” The job supplies the concrete goal and acceptance criteria; its workflow tasks provide the instructions for carrying it out.
40
+
41
+ An **execution** records the task's inputs, participant/session assignment, status, outputs, and outcome within a particular job. Review loops and explicit retries create new executions of the same task. Restarting an agent session continues its existing execution. A session can perform multiple executions; human participants need no agent session. A single-agent job can use a one-task workflow. Each execution records its initial commit, timestamps, and outgoing mailbox messages. Its accepted outcome retains commit messages and diffs alongside the worktree manifest. In task details, double-click a commit or sent message to view its full retained text in a read-only editor window; Enter and Open are also supported.
42
+
43
+ Projects can contain dependent jobs, each with an immutable workflow snapshot and its own worktree/branch. PR identity belongs to the job: assign a repository and PR number, then search by number with an optional repository filter. Workflow completion, PR merge, project completion, and archival are distinct milestones.
44
+
45
+ The OS-specific user data directory owns durable project and job records. Each job worktree exposes its records through `.scratch/ctlrm`, a symlink into the central job directory. See [project/job commands, storage, and PR lookup](https://github.com/d-chambers/ctlrm/blob/main/docs/projects.md) and the [backend implementation plan](https://github.com/d-chambers/ctlrm/blob/main/docs/superpowers/plans/2026-09-05-project-jobs.md). Workflows can request bounded specialist-review tasks from a predefined allowlist. The [ship workflow](https://github.com/d-chambers/ctlrm/blob/main/src/ctlrm/web/templates/ship.yaml) uses review lenses, fresh reviewer sessions, PR publication, and CI/review handling; the [single-agent workflow](https://github.com/d-chambers/ctlrm/blob/main/src/ctlrm/web/templates/single-agent.yaml) keeps simple jobs small. Project completion retires owned processes and retains the accepted code; `project archive` creates a verified ZIP while keeping PR metadata searchable. See [completion and archival](https://github.com/d-chambers/ctlrm/blob/main/docs/projects.md#completion-and-archival).
46
+
47
+ ## Development
48
+
49
+ Use Linux, Python 3.11 or newer, tmux 3.2a or newer, and local POSIX storage. `libtmux` 0.62.x is installed with the package. Install and authenticate the provider CLIs separately. Run `uv sync`, then `uv run ctlrm --help`. Run checks with `uv run pytest --cov ctlrm --cov-report term-missing`, `uv run ruff check .`, `uv run ruff format --check .`, and `uvx prek run --all-files`. Browser assets are packaged locally. After editing frontend source, run `npm --prefix frontend ci`, `npm --prefix frontend run build`, and `npm --prefix frontend run check`; `npm --prefix frontend run format` formats authored assets. Node is needed for frontend development, not to run the installed workbench.
50
+
51
+ ## Releases
52
+
53
+ CI checks pull requests and `main` on Python 3.11 and 3.14. Publishing a GitHub release runs those checks again and uploads the tested packages to PyPI through Trusted Publishing. See [release setup and versioning](https://github.com/d-chambers/ctlrm/blob/main/docs/releases.md), including the one-time PyPI account configuration.
54
+
55
+ ## Managed sessions and workflows
56
+
57
+ ```sh
58
+ ctlrm --root /path/to/worktree session start --provider codex
59
+ ctlrm --root /path/to/worktree session status
60
+ ctlrm workflow validate --template src/ctlrm/web/templates/implement-review.yaml
61
+ ctlrm --root /path/to/another-worktree workflow submit --template src/ctlrm/web/templates/implement-review.yaml --title "Implement the task" --file task.md --request-id my-task
62
+ ctlrm --root /path/to/another-worktree workflow status
63
+ ```
64
+
65
+ Use a fresh worktree for each independent job. The [example template](https://github.com/d-chambers/ctlrm/blob/main/src/ctlrm/web/templates/implement-review.yaml) binds implementer and reviewer roles to separate Codex sessions, then waits for a human owner. Profiles explicitly select provider permissions; Claude automatic input requires an unattended profile. See [session operations and recovery limits](https://github.com/d-chambers/ctlrm/blob/main/docs/managed-sessions.md) and [workflow acknowledgment, approval, retry, and cancellation](https://github.com/d-chambers/ctlrm/blob/main/docs/workflows.md).
66
+
67
+ For project jobs, use `project complete` and `project archive`. To retire a standalone area, explicitly stop every managed session and verify its owned provider processes have exited, then stop the supervisor. Preserve wanted logs and artifacts outside the area before explicitly removing runtime files or the worktree with normal filesystem/Git tools. Supervisor stop alone leaves agents running. Project jobs can create dedicated worktrees automatically. Automatic worktree removal, recycling, parallel workflows in one area, cron, remote delegation, and embedded editing are deferred.
68
+
69
+ ## Room example
70
+
71
+ ```sh
72
+ ctlrm --root /path/to/worktree init --id coordinator --name Coordinator --assign coordinator=coordinate --assign reviewer=review --prompt "Review the change."
73
+ ctlrm --root /path/to/worktree join --id reviewer --name Reviewer
74
+ ctlrm --root /path/to/worktree send --from coordinator --to reviewer --title Review --body "Please review."
75
+ ctlrm --root /path/to/worktree inbox --participant reviewer
76
+ ```
77
+
78
+ Restart commands in room signatures are stored only; use managed sessions for executable recovery. Room identity is cooperative rather than authenticated. All participants need appropriate shared filesystem permissions.
79
+
80
+ ### Conversation input
81
+
82
+ Managed native Codex sessions accept conversation messages between turns with `ctlrm --root WORKTREE session interact --session-id ID --generation N --text "Explain the current change"`. This resumes the recorded native conversation and does not assign, acknowledge, or complete a workflow task. The supervisor accepts up to eight pending messages, each at most 16 KiB. A runner claims each message before invoking the provider; interrupted turns are retained as `uncertain` and are never automatically replayed. Explicitly replacing a conversation cancels its queued messages. Recent messages remain in the session snapshot and older messages remain in the event journal. Interactive providers continue to accept direct input through their owned tmux terminal.
@@ -0,0 +1,203 @@
1
+ {
2
+ "date": "2026-09-06",
3
+ "application": "CSV Brief",
4
+ "description": "Standard-library Python streaming CSV summary CLI",
5
+ "project": "csv-brief",
6
+ "job": "build",
7
+ "provenance": {
8
+ "managed_agent_build": true,
9
+ "provider": "codex",
10
+ "terminal_manager": "libtmux",
11
+ "app_commit": "e0db8affd86cc79ab27253ccbcea3b22749a1c54",
12
+ "runtime_commit": "d0cba76"
13
+ },
14
+ "recovery_checks": [
15
+ {
16
+ "test": "initial live writer checkpoint",
17
+ "at": "2026-09-06T15:20:29Z",
18
+ "generation": 1,
19
+ "native_id": "01a07747-69a5-7e90-b843-0aad144b817a",
20
+ "execution": "execution-257d8cb8c6824a6a85fde7c75120d470",
21
+ "files": 5
22
+ },
23
+ {
24
+ "test": "automatic recovery after provider death",
25
+ "at": "2026-09-06T15:22:15Z",
26
+ "generation": 2,
27
+ "same_native_id": true,
28
+ "same_execution": true,
29
+ "uncommitted_files_preserved": true,
30
+ "killed_owned_processes": 3,
31
+ "exit_status": -9
32
+ },
33
+ {
34
+ "test": "supervisor crash and restart",
35
+ "at": "2026-09-06T15:22:15Z",
36
+ "agent_generation_unchanged": true,
37
+ "agent_process_identity_unchanged": true,
38
+ "same_execution": true,
39
+ "uncommitted_files_preserved": true
40
+ },
41
+ {
42
+ "test": "automatic recovery after terminal loss",
43
+ "at": "2026-09-06T15:23:55Z",
44
+ "generation": 3,
45
+ "same_native_id": true,
46
+ "same_execution": true,
47
+ "uncommitted_files_preserved": true
48
+ },
49
+ {
50
+ "test": "explicit stop suppresses automatic restart",
51
+ "at": "2026-09-06T15:23:59Z",
52
+ "generation": 3,
53
+ "repeated_request_idempotent": true
54
+ },
55
+ {
56
+ "test": "explicit native resume",
57
+ "at": "2026-09-06T15:25:46Z",
58
+ "generation": 4,
59
+ "same_native_id": true,
60
+ "same_execution": true,
61
+ "uncommitted_files_preserved": true
62
+ },
63
+ {
64
+ "test": "stale generation rejected",
65
+ "at": "2026-09-06T15:25:46Z",
66
+ "current_generation": 4,
67
+ "old_generation": 3,
68
+ "current_process_preserved": true
69
+ },
70
+ {
71
+ "test": "writer released after faults",
72
+ "at": "2026-09-06T15:25:46Z"
73
+ },
74
+ {
75
+ "test": "explicit fresh-session replacement",
76
+ "at": "2026-09-06T15:34:23Z",
77
+ "generation": 2,
78
+ "new_native_id": true,
79
+ "same_review_execution": true,
80
+ "same_input_artifact": true,
81
+ "code_unchanged": true
82
+ },
83
+ {
84
+ "test": "one implementation and one review handoff",
85
+ "at": "2026-09-06T15:36:03Z",
86
+ "tasks": [
87
+ {
88
+ "task": "implement",
89
+ "status": "completed",
90
+ "outcome": "completed",
91
+ "execution": "execution-257d8cb8c6824a6a85fde7c75120d470"
92
+ },
93
+ {
94
+ "task": "review",
95
+ "status": "completed",
96
+ "outcome": "approved",
97
+ "execution": "execution-8b20888aa86443869c3627cb4735ff9d"
98
+ },
99
+ {
100
+ "task": "counterpart",
101
+ "status": "pending",
102
+ "outcome": null,
103
+ "execution": "execution-0829201f9f564bc585eb34852c0c8a89"
104
+ }
105
+ ],
106
+ "commit": "e0db8affd86cc79ab27253ccbcea3b22749a1c54",
107
+ "worktree_clean": true
108
+ }
109
+ ],
110
+ "final_checks": {
111
+ "completed_writer_resumed_same_native_session": true,
112
+ "writer_final_generation": 5,
113
+ "completed_task_not_reopened": true,
114
+ "no_duplicate_task_or_commit": true,
115
+ "implementation_commits": 1,
116
+ "unchanged_commit": "e0db8affd86cc79ab27253ccbcea3b22749a1c54",
117
+ "all_agent_sessions_stopped": true,
118
+ "supervisor_stopped": true,
119
+ "tmux_sessions_remaining": 0,
120
+ "processes_in_app_worktree": [],
121
+ "counterpart_gate": "pending"
122
+ },
123
+ "task_artifacts": [
124
+ {
125
+ "task": "implement",
126
+ "items": [
127
+ {
128
+ "kind": "commit",
129
+ "id": "commit-bcd2e031bc052bc23b118af27aff3e7d0e0a58399947a2aef544fbec404c3405"
130
+ },
131
+ {
132
+ "kind": "message",
133
+ "id": "msg-20260906T152656-24f1ff5e"
134
+ },
135
+ {
136
+ "kind": "report",
137
+ "id": "execution-257d8cb8c6824a6a85fde7c75120d470"
138
+ }
139
+ ]
140
+ },
141
+ {
142
+ "task": "review",
143
+ "items": [
144
+ {
145
+ "kind": "commit",
146
+ "id": "commit-bcd2e031bc052bc23b118af27aff3e7d0e0a58399947a2aef544fbec404c3405"
147
+ },
148
+ {
149
+ "kind": "message",
150
+ "id": "msg-20260906T153546-3237d120"
151
+ },
152
+ {
153
+ "kind": "report",
154
+ "id": "execution-8b20888aa86443869c3627cb4735ff9d"
155
+ }
156
+ ]
157
+ }
158
+ ],
159
+ "validation": {
160
+ "app_tests_passed": 14,
161
+ "app_cli_acceptance_passed": 13,
162
+ "runtime_tests_passed": 41,
163
+ "ruff": "passed",
164
+ "prek": "passed",
165
+ "independent_review": "approved with no actionable findings"
166
+ },
167
+ "scope": {
168
+ "counterpart_review": "pending source-transmission approval",
169
+ "remote_pr_and_ci": "not exercised; no remote was configured",
170
+ "not_exercised": [
171
+ "machine reboot",
172
+ "provider credential or network outage",
173
+ "different interpreter installation path",
174
+ "crash before native recovery registration"
175
+ ]
176
+ },
177
+ "source_evidence": [
178
+ {
179
+ "file": "recovery-checks.json",
180
+ "sha256": "5f3a61f2d485bf9b1e3dd7695381d2cfdd147230351181318d6be41bc9b4b032"
181
+ },
182
+ {
183
+ "file": "final-acceptance.json",
184
+ "sha256": "0483a05d81cd0d76c5818a91da3fa3f6d79d0a52236f2b4e788bb228c39207c6"
185
+ },
186
+ {
187
+ "file": "app-acceptance.json",
188
+ "sha256": "2332c8f8cad6dfafec7dfcbb5519a83d71663e93906d50b41fb1fcd3671d22d8"
189
+ },
190
+ {
191
+ "file": "app-tests.txt",
192
+ "sha256": "189ba3e93109df5c0e2844a310a6be7d2a2f21d45cad6afe125bf9815602596f"
193
+ },
194
+ {
195
+ "file": "runtime-tests.txt",
196
+ "sha256": "d77b1376218e38d6643d1705fad4ef31f241e9c801355fbe10d4e315b14aae91"
197
+ },
198
+ {
199
+ "file": "runtime-lint.txt",
200
+ "sha256": "84617e5ab13858c275ee0228d2588844cac631a8dce9f3d2dadc36a8d5320d67"
201
+ }
202
+ ]
203
+ }
@@ -0,0 +1 @@
1
+ {"area_id":"area-5bac55c1489946ee91ed5af7ed47320c","at":"2026-09-05T09:04:44.328906+00:00","context_token_recalled":true,"final_session":"stopped","initial_generation":1,"native_id":"01a070cd-2b8a-7170-bf30-64ac34c353e6","provider":"codex-cli 0.153.4","resumed_generation":2,"session_id":"session-b116ebd7feca4c7cb8171aada15534d9","status":"completed","work_id":"work-60cb312d51774f0988fc283e9e69edef"}
@@ -0,0 +1 @@
1
+ {"area_id":"area-439baa3c8c9543fcaad869f78a661653","completed_at":"2026-09-05T08:17:59.603639+00:00","exit_observation":"{\"returncode\":-9,\"token\":\"launch-acdf98f7971f4d4a9251e4476f6d32e5\"}\n","final_session_status":"stopped","final_work_status":"completed","interrupted_generation":3,"kill_at":"2026-09-05T08:17:35.270240+00:00","native_id":"540f01be-c322-4bcf-bcd1-3c2a5b75f0bd","provider_pid":194934,"recovered_generation":4,"session_id":"session-d6917cd078db429fa8bed5a9d49211e7","work_id":"work-582c13ff8d384649983051e0834075e7","work_status_at_kill":"acknowledged"}
@@ -0,0 +1 @@
1
+ {"area_id":"area-439baa3c8c9543fcaad869f78a661653","completed_at":"2026-09-05T07:33:56.802582+00:00","explicit_stop_at":"2026-09-05T07:34:41.853755+00:00","final_generation":2,"final_status":"stopped","initial_generation":1,"initial_recovery":{"area_id":"area-439baa3c8c9543fcaad869f78a661653","at":"2026-09-05T07:28:24.041481+00:00","context":"/home/derrick/.claude","executable":"/home/derrick/.local/bin/claude","generation":1,"native_id":"540f01be-c322-4bcf-bcd1-3c2a5b75f0bd","required_environment":[],"resume_argv":["/home/derrick/.local/bin/claude","--permission-mode","dontAsk","--tools","Read,Bash","--allowedTools","Read,Bash(/tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-managed-native:*)","--resume","540f01be-c322-4bcf-bcd1-3c2a5b75f0bd",""],"root":"/tmp/ctlrm-managed-native","schema_version":1,"session_id":"session-d6917cd078db429fa8bed5a9d49211e7"},"initial_work":{"generation":1,"id":"work-0a7ea1c14e084de0bfda23db95b861a9","message":{"body":"Work ID: work-0a7ea1c14e084de0bfda23db95b861a9\nAcknowledge this work ID before acting.\n\nRemember the exact token IRIS-7382 in this conversation. Acknowledge this work ID before acting. Then report completed with the documented session disposition command. Do not edit files or poll.","created_at":"2026-09-05T07:29:53.806863+00:00","files":[],"from":"coordinator","id":"msg-9338beba8e8546668a51ad65e41f55b8","kind":"prompt","node_id":null,"run_id":null,"status":"pending","title":"prompt","to":"agent","workflow_id":null},"status":"completed"},"killed_at":"2026-09-05T07:31:17.481761+00:00","native_id":"540f01be-c322-4bcf-bcd1-3c2a5b75f0bd","provider_process":"157014:850395","recall_work":{"generation":2,"id":"work-515bc22c1858446ab0e409d74446d342","message":{"body":"Work ID: work-515bc22c1858446ab0e409d74446d342\nAcknowledge this work ID before acting.\n\nWithout opening old mailbox messages or any other files, recall the exact acceptance token from the previous completed prompt in this native conversation and print it in your response. Acknowledge this work ID first and report completed afterward. Only read this current assignment and use the documented ctlrm commands. Do not poll.","created_at":"2026-09-05T07:32:21.946279+00:00","files":[],"from":"coordinator","id":"msg-f282df14eb214504a9dad380bbe4f18a","kind":"prompt","node_id":null,"run_id":null,"status":"pending","title":"prompt","to":"agent","workflow_id":null},"status":"completed"},"resumed_generation":2,"resumed_native_id":"540f01be-c322-4bcf-bcd1-3c2a5b75f0bd","resumed_recovery":{"area_id":"area-439baa3c8c9543fcaad869f78a661653","at":"2026-09-05T07:31:48.001959+00:00","context":"/home/derrick/.claude","executable":"/home/derrick/.local/bin/claude","generation":2,"native_id":"540f01be-c322-4bcf-bcd1-3c2a5b75f0bd","required_environment":[],"resume_argv":["/home/derrick/.local/bin/claude","--permission-mode","dontAsk","--tools","Read,Bash","--allowedTools","Read,Bash(/tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-managed-native:*)","--resume","540f01be-c322-4bcf-bcd1-3c2a5b75f0bd",""],"root":"/tmp/ctlrm-managed-native","schema_version":1,"session_id":"session-d6917cd078db429fa8bed5a9d49211e7"},"root":"/tmp/ctlrm-managed-native","session_id":"session-d6917cd078db429fa8bed5a9d49211e7","signal":"SIGKILL"}
@@ -0,0 +1 @@
1
+ {"area_id":"area-dcbf097538734122960a5b612e277636","at":"2026-09-05T09:12:15.847055+00:00","final_output":"version two","handoff_supervisor_restart":true,"human_response":"exercised by acceptance controller","interrupted_execution":"execution-7edfb41a22c645149b86086b20110f8a","native_implementer":"01a070d1-f394-75d0-9fe7-13e13ddf6e22","recovered_generation":2,"run":{"active":null,"executions":[{"artifact":"artifact-3a808a7cd8b04730ae4f679d86c30919502cb1f0cfc9d42884c6a91ca3a871e9","generation":2,"id":"execution-7edfb41a22c645149b86086b20110f8a","input":{},"message":{"body":"Area: area-dcbf097538734122960a5b612e277636\nRun: run-74e3b4884e844374a6c4ef9894c065ad\nWork ID: execution-7edfb41a22c645149b86086b20110f8a\nRole instructions: This is a bounded ctlrm protocol acceptance test. Only edit acceptance.txt. No repository implementation work or code review subprocesses are requested. Always follow assignment acknowledgment/report commands. On the FIRST implement visit, acknowledge, write acceptance.txt with exactly version one, then end your turn WITHOUT reporting completion. The controller will interrupt and natively resume you. In the resumed generation, acknowledge readiness, reconcile as in_progress, acknowledge this same execution using the current generation, then report completed. Do not rewrite the existing version one file after recovery. On a later implement visit triggered by changes_requested, write exactly version two and report completed normally. Never act as the human owner.\nTask: .ctlrm/task.md\nInput: {}\nAllowed outcomes: completed\nBefore acting, run: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow acknowledge --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-7edfb41a22c645149b86086b20110f8a --participant implementer --session-id session-1e23fc2d53e144a89602c4d51f80e503 --generation 1\nReport with: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow report --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-7edfb41a22c645149b86086b20110f8a --participant implementer --session-id session-1e23fc2d53e144a89602c4d51f80e503 --generation 1 --outcome OUTCOME --summary SUMMARY\nAfter native resume use your CURRENT generation in these commands. Do not choose the next recipient; the workflow routes accepted outcomes. After an accepted report, finish your turn and wait; do not perform further work.","created_at":"2026-09-05T09:07:26.747440+00:00","files":[],"from":"coordinator","id":"msg-745f6060b3ef4d37835410bebd1aca1e","kind":"assignment","node_id":null,"run_id":null,"status":"pending","title":"assignment","to":"implementer","workflow_id":null},"outcome":"completed","participant":"implementer","session_id":"session-1e23fc2d53e144a89602c4d51f80e503","status":"completed","step":"implement","summary":"Reconciled as in_progress and acknowledged in generation 2. Verified acceptance.txt contains exactly version one without rewriting it."},{"artifact":"artifact-21550c592394dee7a54f4e234eeaa3deb49385749322a851d545316473fb04b7","generation":1,"id":"execution-af1ac02a58734ee58c75f535ecd72d1d","input":{"artifact":"artifact-3a808a7cd8b04730ae4f679d86c30919502cb1f0cfc9d42884c6a91ca3a871e9","execution_id":"execution-7edfb41a22c645149b86086b20110f8a","outcome":"completed","summary":"Reconciled as in_progress and acknowledged in generation 2. Verified acceptance.txt contains exactly version one without rewriting it."},"message":{"body":"Area: area-dcbf097538734122960a5b612e277636\nRun: run-74e3b4884e844374a6c4ef9894c065ad\nWork ID: execution-af1ac02a58734ee58c75f535ecd72d1d\nRole instructions: Bounded protocol acceptance test. Read acceptance.txt and acknowledge the exact input artifact. If it says version one, report changes_requested with summary Change acceptance.txt to exactly version two. If it says version two, report approved with summary Version two verified. Do not modify any files and do not run another review agent. Use the supplied workflow acknowledgment/report commands with your current generation. Never act as the human owner.\nTask: .ctlrm/task.md\nInput: {\"artifact\": \"artifact-3a808a7cd8b04730ae4f679d86c30919502cb1f0cfc9d42884c6a91ca3a871e9\", \"execution_id\": \"execution-7edfb41a22c645149b86086b20110f8a\", \"outcome\": \"completed\", \"summary\": \"Reconciled as in_progress and acknowledged in generation 2. Verified acceptance.txt contains exactly version one without rewriting it.\"}\nAllowed outcomes: approved, changes_requested\nBefore acting, run: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow acknowledge --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-af1ac02a58734ee58c75f535ecd72d1d --participant reviewer --session-id session-3bd4551d3215426287a69e82a2845b81 --generation 1 --input-artifact artifact-3a808a7cd8b04730ae4f679d86c30919502cb1f0cfc9d42884c6a91ca3a871e9\nReport with: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow report --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-af1ac02a58734ee58c75f535ecd72d1d --participant reviewer --session-id session-3bd4551d3215426287a69e82a2845b81 --generation 1 --input-artifact artifact-3a808a7cd8b04730ae4f679d86c30919502cb1f0cfc9d42884c6a91ca3a871e9 --outcome OUTCOME --summary SUMMARY\nAfter native resume use your CURRENT generation in these commands. Do not choose the next recipient; the workflow routes accepted outcomes. After an accepted report, finish your turn and wait; do not perform further work.","created_at":"2026-09-05T09:10:33.547900+00:00","files":[],"from":"coordinator","id":"msg-cea145f2be0c421296b1f64ed9c3bfb9","kind":"assignment","node_id":null,"run_id":null,"status":"pending","title":"assignment","to":"reviewer","workflow_id":null},"outcome":"changes_requested","participant":"reviewer","session_id":"session-3bd4551d3215426287a69e82a2845b81","status":"completed","step":"review","summary":"Change acceptance.txt to exactly version two"},{"artifact":"artifact-29f8a96dc842cb5a351514c06da7b6f05bf828c29f2c7bf84cc21f6eb29340d2","generation":2,"id":"execution-01d6eba5e01a4cb0af250761664a59f6","input":{"artifact":"artifact-21550c592394dee7a54f4e234eeaa3deb49385749322a851d545316473fb04b7","execution_id":"execution-af1ac02a58734ee58c75f535ecd72d1d","outcome":"changes_requested","summary":"Change acceptance.txt to exactly version two"},"message":{"body":"Area: area-dcbf097538734122960a5b612e277636\nRun: run-74e3b4884e844374a6c4ef9894c065ad\nWork ID: execution-01d6eba5e01a4cb0af250761664a59f6\nRole instructions: This is a bounded ctlrm protocol acceptance test. Only edit acceptance.txt. No repository implementation work or code review subprocesses are requested. Always follow assignment acknowledgment/report commands. On the FIRST implement visit, acknowledge, write acceptance.txt with exactly version one, then end your turn WITHOUT reporting completion. The controller will interrupt and natively resume you. In the resumed generation, acknowledge readiness, reconcile as in_progress, acknowledge this same execution using the current generation, then report completed. Do not rewrite the existing version one file after recovery. On a later implement visit triggered by changes_requested, write exactly version two and report completed normally. Never act as the human owner.\nTask: .ctlrm/task.md\nInput: {\"execution_id\": \"execution-af1ac02a58734ee58c75f535ecd72d1d\", \"outcome\": \"changes_requested\", \"summary\": \"Change acceptance.txt to exactly version two\", \"artifact\": \"artifact-21550c592394dee7a54f4e234eeaa3deb49385749322a851d545316473fb04b7\"}\nAllowed outcomes: completed\nBefore acting, run: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow acknowledge --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-01d6eba5e01a4cb0af250761664a59f6 --participant implementer --session-id session-1e23fc2d53e144a89602c4d51f80e503 --generation 2 --input-artifact artifact-21550c592394dee7a54f4e234eeaa3deb49385749322a851d545316473fb04b7\nReport with: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow report --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-01d6eba5e01a4cb0af250761664a59f6 --participant implementer --session-id session-1e23fc2d53e144a89602c4d51f80e503 --generation 2 --input-artifact artifact-21550c592394dee7a54f4e234eeaa3deb49385749322a851d545316473fb04b7 --outcome OUTCOME --summary SUMMARY\nAfter native resume use your CURRENT generation in these commands. Do not choose the next recipient; the workflow routes accepted outcomes. After an accepted report, finish your turn and wait; do not perform further work.","created_at":"2026-09-05T09:10:50.277924+00:00","files":[],"from":"coordinator","id":"msg-ee19c4fbe2384019991dbafa9390df2b","kind":"assignment","node_id":null,"run_id":null,"status":"pending","title":"assignment","to":"implementer","workflow_id":null},"outcome":"completed","participant":"implementer","session_id":"session-1e23fc2d53e144a89602c4d51f80e503","status":"completed","step":"implement","summary":"Changed acceptance.txt to exactly version two and verified its exact bytes."},{"artifact":"artifact-c321e643b05bb8c8cc288018d93a011185d8cfa13bf544657e3cc4194684aee1","generation":1,"id":"execution-e7a895f0890d450ca0a3ba48eb605cfd","input":{"artifact":"artifact-29f8a96dc842cb5a351514c06da7b6f05bf828c29f2c7bf84cc21f6eb29340d2","execution_id":"execution-01d6eba5e01a4cb0af250761664a59f6","outcome":"completed","summary":"Changed acceptance.txt to exactly version two and verified its exact bytes."},"message":{"body":"Area: area-dcbf097538734122960a5b612e277636\nRun: run-74e3b4884e844374a6c4ef9894c065ad\nWork ID: execution-e7a895f0890d450ca0a3ba48eb605cfd\nRole instructions: Bounded protocol acceptance test. Read acceptance.txt and acknowledge the exact input artifact. If it says version one, report changes_requested with summary Change acceptance.txt to exactly version two. If it says version two, report approved with summary Version two verified. Do not modify any files and do not run another review agent. Use the supplied workflow acknowledgment/report commands with your current generation. Never act as the human owner.\nTask: .ctlrm/task.md\nInput: {\"execution_id\": \"execution-01d6eba5e01a4cb0af250761664a59f6\", \"outcome\": \"completed\", \"summary\": \"Changed acceptance.txt to exactly version two and verified its exact bytes.\", \"artifact\": \"artifact-29f8a96dc842cb5a351514c06da7b6f05bf828c29f2c7bf84cc21f6eb29340d2\"}\nAllowed outcomes: approved, changes_requested\nBefore acting, run: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow acknowledge --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-e7a895f0890d450ca0a3ba48eb605cfd --participant reviewer --session-id session-3bd4551d3215426287a69e82a2845b81 --generation 1 --input-artifact artifact-29f8a96dc842cb5a351514c06da7b6f05bf828c29f2c7bf84cc21f6eb29340d2\nReport with: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow report --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-e7a895f0890d450ca0a3ba48eb605cfd --participant reviewer --session-id session-3bd4551d3215426287a69e82a2845b81 --generation 1 --input-artifact artifact-29f8a96dc842cb5a351514c06da7b6f05bf828c29f2c7bf84cc21f6eb29340d2 --outcome OUTCOME --summary SUMMARY\nAfter native resume use your CURRENT generation in these commands. Do not choose the next recipient; the workflow routes accepted outcomes. After an accepted report, finish your turn and wait; do not perform further work.","created_at":"2026-09-05T09:11:49.072292+00:00","files":[],"from":"coordinator","id":"msg-6316c2609e874c32bbf2b82d8003d98d","kind":"assignment","node_id":null,"run_id":null,"status":"pending","title":"assignment","to":"reviewer","workflow_id":null},"outcome":"approved","participant":"reviewer","session_id":"session-3bd4551d3215426287a69e82a2845b81","status":"completed","step":"review","summary":"Version two verified"},{"artifact":"artifact-cfa8a12a6fe891eba8425a22bcde66e427b475c60456dfb506ef12803dcb2421","generation":null,"id":"execution-9592c63076df4f4c9cae4097b08374d1","input":{"artifact":"artifact-c321e643b05bb8c8cc288018d93a011185d8cfa13bf544657e3cc4194684aee1","execution_id":"execution-e7a895f0890d450ca0a3ba48eb605cfd","outcome":"approved","summary":"Version two verified"},"message":{"body":"Area: area-dcbf097538734122960a5b612e277636\nRun: run-74e3b4884e844374a6c4ef9894c065ad\nWork ID: execution-9592c63076df4f4c9cae4097b08374d1\nRole instructions: Accept the final version after the review loop.\nTask: .ctlrm/task.md\nInput: {\"execution_id\": \"execution-e7a895f0890d450ca0a3ba48eb605cfd\", \"outcome\": \"approved\", \"summary\": \"Version two verified\", \"artifact\": \"artifact-c321e643b05bb8c8cc288018d93a011185d8cfa13bf544657e3cc4194684aee1\"}\nAllowed outcomes: approved\nBefore acting, run: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow acknowledge --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-9592c63076df4f4c9cae4097b08374d1 --participant owner --input-artifact artifact-c321e643b05bb8c8cc288018d93a011185d8cfa13bf544657e3cc4194684aee1\nReport with: /tmp/ctlrm-implementation/.venv/bin/python3 -m ctlrm --root /tmp/ctlrm-mixed-native workflow report --run-id run-74e3b4884e844374a6c4ef9894c065ad --execution-id execution-9592c63076df4f4c9cae4097b08374d1 --participant owner --input-artifact artifact-c321e643b05bb8c8cc288018d93a011185d8cfa13bf544657e3cc4194684aee1 --outcome OUTCOME --summary SUMMARY\nAfter native resume use your CURRENT generation in these commands. Do not choose the next recipient; the workflow routes accepted outcomes. After an accepted report, finish your turn and wait; do not perform further work.","created_at":"2026-09-05T09:12:11.489732+00:00","files":[],"from":"coordinator","id":"msg-faef987c47e54fafa6919d466cfd281e","kind":"assignment","node_id":null,"run_id":null,"status":"pending","title":"assignment","to":"owner","workflow_id":null},"outcome":"approved","participant":"owner","session_id":null,"status":"completed","step":"approve","summary":"Acceptance controller verified version two and exercised the human response API."}],"id":"run-74e3b4884e844374a6c4ef9894c065ad","reason":null,"status":"completed","task_id":"task-6d7369d3d346443eb9747bae13ae9f95"},"second_area_canceled_before_launch":true,"second_area_id":"area-213057c5365e4a0eb75fd48969b7f981","sessions_explicitly_stopped":true,"unchanged_template_reused":true}