ace-coworker 0.6.2 → 0.8.0
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.
- checksums.yaml +4 -4
- data/.ace-defaults/coworker/roles/bootstrap-verifier.yml +12 -0
- data/.ace-defaults/coworker/roles/bootstrap-worker.yml +12 -0
- data/.ace-defaults/coworker/roles/second-captain.yml +18 -0
- data/.ace-defaults/coworker/sequences/bootstrap-verifier.yml +11 -0
- data/.ace-defaults/coworker/sequences/bootstrap-worker.yml +11 -0
- data/CHANGELOG.md +33 -0
- data/README.md +2 -1
- data/docs/usage.md +48 -19
- data/handbook/workflow-instructions/coworker/bootstrap-verifier.wf.md +52 -0
- data/handbook/workflow-instructions/coworker/bootstrap-worker.wf.md +53 -0
- data/handbook/workflow-instructions/coworker/integrator.wf.md +6 -2
- data/handbook/workflow-instructions/coworker/second-captain.wf.md +88 -0
- data/lib/ace/coworker/atoms/config_schema.rb +1 -0
- data/lib/ace/coworker/atoms/integration_gate.rb +59 -12
- data/lib/ace/coworker/atoms/prompt_template.rb +3 -1
- data/lib/ace/coworker/cli/commands/commission.rb +2 -1
- data/lib/ace/coworker/cli/commands/gate.rb +21 -5
- data/lib/ace/coworker/organisms/commission_orchestrator.rb +16 -6
- data/lib/ace/coworker/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b33e4050f914bca417193b67ba22d076a9a7866a89d1d3465fe6fb344f7bca7d
|
|
4
|
+
data.tar.gz: 1cba8a3b7b85957083d95da14d5cf2fb44988ebc2b7efdc8537b24eda096612b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c4cb31c35e64be7767cf08f12fc9609c788d9d174c7dec0e72077e16721a17670028f57ed0641d422402d70af8f8f2c32bb3304e5b455cf1b8fb20aef340965
|
|
7
|
+
data.tar.gz: 8f66afb6f9f8c9d8ceb877ff369b920860a509705356a9b6eca0f1a42aada2b2879dba2e4c028a23956dc528515f7fc48768e56a7b50e5b9d181df211f4027ff
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bootstrap-verifier
|
|
3
|
+
description: Independently verify the prepared canonical project without repairing it
|
|
4
|
+
instructions: wfi://coworker/bootstrap-verifier
|
|
5
|
+
start_prompt: >-
|
|
6
|
+
Work as {{role}} on task {{task}} and pinned assignment {{assignment}}.
|
|
7
|
+
Read the explicit canonical target and allowed operations from the commission.
|
|
8
|
+
Report verified evidence to {{overseer}}; never update its private task tree.
|
|
9
|
+
reporting:
|
|
10
|
+
channel: hitl
|
|
11
|
+
errors:
|
|
12
|
+
on_failure: report
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bootstrap-worker
|
|
3
|
+
description: Prepare the explicitly commissioned canonical project configuration
|
|
4
|
+
instructions: wfi://coworker/bootstrap-worker
|
|
5
|
+
start_prompt: >-
|
|
6
|
+
Work as {{role}} on task {{task}} and pinned assignment {{assignment}}.
|
|
7
|
+
Read the explicit canonical target and allowed operations from the commission.
|
|
8
|
+
Report verified evidence to {{overseer}}; never update its private task tree.
|
|
9
|
+
reporting:
|
|
10
|
+
channel: hitl
|
|
11
|
+
errors:
|
|
12
|
+
on_failure: report
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Second Captain role preset (shipped gem defaults, overridable per project
|
|
3
|
+
# via .ace/coworker/roles/second-captain.yml). Advisory ONLY: delegated per
|
|
4
|
+
# HITL case to propose a marked answer with rationale and grounds (task
|
|
5
|
+
# 8xs.t.pu0.b). Never answers in the human's name, never approves or gates
|
|
6
|
+
# work, never touches secret/OTP cases.
|
|
7
|
+
name: second-captain
|
|
8
|
+
description: Advisory Second Captain; proposes one marked answer with rationale and grounds into the exact HITL case and stops — never a human decision, approval, or gate
|
|
9
|
+
instructions: wfi://coworker/second-captain
|
|
10
|
+
start_prompt: >-
|
|
11
|
+
Work as the {{role}} on case {{case}} (task {{task}}): read the exact HITL
|
|
12
|
+
case and its referenced evidence, write one marked suggestion with
|
|
13
|
+
rationale and grounds through assignment {{assignment}}, reporting to the
|
|
14
|
+
overseer at {{overseer}} — then stop.
|
|
15
|
+
reporting:
|
|
16
|
+
channel: hitl
|
|
17
|
+
errors:
|
|
18
|
+
on_failure: report
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
role: bootstrap-verifier
|
|
3
|
+
description: "Independently verify the prepared canonical project without repairing it for task {{task}}"
|
|
4
|
+
outcome: "Task {{task}} has an evidence-backed bootstrap-verifier result for its exact canonical target."
|
|
5
|
+
steps:
|
|
6
|
+
- name: bootstrap-verifier
|
|
7
|
+
workflow: wfi://coworker/bootstrap-verifier
|
|
8
|
+
instructions:
|
|
9
|
+
- "Independently verify the prepared canonical project without repairing it for task {{task}} under the scoped bootstrap role workflow."
|
|
10
|
+
- "Record actual checks, canonical target, operational runtime paths/versions and failures in the task evidence."
|
|
11
|
+
- "Fail the assignment on missing scope, missing required access or failed acceptance; never force success."
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
role: bootstrap-worker
|
|
3
|
+
description: "Prepare the explicitly commissioned canonical project configuration for task {{task}}"
|
|
4
|
+
outcome: "Task {{task}} has an evidence-backed bootstrap-worker result for its exact canonical target."
|
|
5
|
+
steps:
|
|
6
|
+
- name: bootstrap-worker
|
|
7
|
+
workflow: wfi://coworker/bootstrap-worker
|
|
8
|
+
instructions:
|
|
9
|
+
- "Prepare the explicitly commissioned canonical project configuration for task {{task}} under the scoped bootstrap role workflow."
|
|
10
|
+
- "Record actual checks, canonical target, operational runtime paths/versions and failures in the task evidence."
|
|
11
|
+
- "Fail the assignment on missing scope, missing required access or failed acceptance; never force success."
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-10-31
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Scoped bootstrap-worker and independent bootstrap-verifier roles use existing
|
|
15
|
+
assignments to prepare an explicitly commissioned canonical project outside
|
|
16
|
+
the lab task worktree, without relaxing ordinary product worker boundaries.
|
|
17
|
+
|
|
18
|
+
## [0.7.0] - 2026-10-30
|
|
19
|
+
|
|
20
|
+
### Fixed (review rounds 3/3b)
|
|
21
|
+
|
|
22
|
+
- The integration gate rejects anonymous formal approvals (empty approver);
|
|
23
|
+
`commission --hitl-case CASE_ID` renders `{{case}}` for per-case presets.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- `second-captain` advisory role preset + `wfi://coworker/second-captain`
|
|
28
|
+
workflow (task 8xs.t.pu0.b): delegated per HITL case to write one marked
|
|
29
|
+
suggestion and stop; never answers in the human's name, approves, gates
|
|
30
|
+
work, or touches secret cases.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Integration gate binds ALL evidence to the exact candidate head (task
|
|
35
|
+
8xs.t.pu0.8): test evidence must carry the head it covered (bare
|
|
36
|
+
executed/passed blocks; a different tested head is stale evidence), and the
|
|
37
|
+
formal approval — `--approval-head`/`--approval-by` — must name the same
|
|
38
|
+
head and come from an account other than the author. The integrator
|
|
39
|
+
re-reads the HEAD immediately before merging through the merge adapter's
|
|
40
|
+
expected-head condition, so the gate-to-merge race refuses a stale
|
|
41
|
+
candidate. CI stays advisory.
|
|
42
|
+
|
|
10
43
|
## [0.6.2] - 2026-10-23
|
|
11
44
|
|
|
12
45
|
### Added
|
data/README.md
CHANGED
|
@@ -23,8 +23,9 @@ ace-coworker resume [--dry-run] # Resume interrupted work in this
|
|
|
23
23
|
ace-coworker prepare --task REF --roles worker,reviewer [--to ADDR] [--dry-run]
|
|
24
24
|
ace-coworker roles # List role presets (gem + project)
|
|
25
25
|
ace-coworker commission --role worker --task REF --assignment ID --overseer ADDR
|
|
26
|
+
[--hitl-case CASE_ID] # renders {{case}} in per-case presets
|
|
26
27
|
ace-coworker gate --candidate-head SHA --review-head SHA --review-verdict accept
|
|
27
|
-
--tests executed,passed --dep LEAF=integrated
|
|
28
|
+
--tests executed,passed --tests-head SHA --dep LEAF=integrated
|
|
28
29
|
```
|
|
29
30
|
|
|
30
31
|
- `prepare` — the planner side: accept a preparation commission (task +
|
data/docs/usage.md
CHANGED
|
@@ -171,28 +171,42 @@ errors, non-zero exit).
|
|
|
171
171
|
```
|
|
172
172
|
ace-coworker gate --review-verdict accept|continue|escalate
|
|
173
173
|
[--candidate-head SHA] [--review-head SHA]
|
|
174
|
-
[--tests executed,passed] [--
|
|
174
|
+
[--tests executed,passed] [--tests-head SHA]
|
|
175
|
+
[--approval-head SHA --approval-by ACCOUNT] [--author ACCOUNT]
|
|
176
|
+
[--dep LEAF=integrated|missing ...]
|
|
175
177
|
[--format table|json] [-q] [-d]
|
|
176
178
|
```
|
|
177
179
|
|
|
178
|
-
The integrator role's pre-merge gate (8xg.t.sbz.4.3
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
`--dep`
|
|
194
|
-
|
|
195
|
-
|
|
180
|
+
The integrator role's pre-merge gate (8xg.t.sbz.4.3; HEAD binding of
|
|
181
|
+
evidence per 8xs.t.pu0.8): a pure, stateless evaluation of the
|
|
182
|
+
project-defined checks. `--candidate-head` is the current candidate head
|
|
183
|
+
(omit it when genuinely unknown - the gate then blocks on the missing
|
|
184
|
+
evidence instead of guessing); `--review-head` is the candidate head the
|
|
185
|
+
independent review verdict covers; `--tests-head` is the head the
|
|
186
|
+
executed test run covered — test evidence without a head, or bound to a
|
|
187
|
+
different head, BLOCKS the merge (a code change or rebase after the tests
|
|
188
|
+
invalidates that basis); `--approval-head`/`--approval-by` supply the
|
|
189
|
+
formal approval's head and account for lanes that require one (an
|
|
190
|
+
approval bound to another head blocks, and an approval by the AUTHOR's
|
|
191
|
+
own account blocks — the formal approver is a different configured lane
|
|
192
|
+
account); each `--dep NAME=integrated|missing` pair states one
|
|
193
|
+
dependency leaf (`missing` or any other value = not integrated; the pair
|
|
194
|
+
must contain `=`, and repeating a name is an error). Empty or omitted
|
|
195
|
+
`--dep` means the caller enumerated no dependencies - the gate trusts the
|
|
196
|
+
caller's dependency enumeration. Prints `ready` or `blocked` with
|
|
197
|
+
per-check reasons (dependencies, candidate drift, review
|
|
198
|
+
freshness/verdict, executed+passing+HEAD-bound tests, formal approval).
|
|
199
|
+
`blocked` is a legitimate gate outcome (exit 0) - the role withholds the
|
|
200
|
+
merge and escalates; only malformed input (an invalid `--dep` pair, a
|
|
201
|
+
duplicate `--dep` name, or an invalid `--tests` token) fails with a
|
|
202
|
+
non-zero exit. Heads are recorded and compared as full lowercase SHAs.
|
|
203
|
+
Nothing is persisted and no git operation is performed: the gate decides
|
|
204
|
+
readiness only — the integrator reads the current HEAD immediately
|
|
205
|
+
before merging and passes it as the merge adapter's expected-head
|
|
206
|
+
condition, so a candidate that moves between gate and merge is refused
|
|
207
|
+
by the adapter (the race never merges a stale candidate). CI status is
|
|
208
|
+
advisory (Captain's decision): a red CI does not block a merge backed by
|
|
209
|
+
executed passing tests and an accepting independent review.
|
|
196
210
|
|
|
197
211
|
### `ace-coworker commission`
|
|
198
212
|
|
|
@@ -573,3 +587,18 @@ does not substitute for provider approval. Accounts and credentials come from
|
|
|
573
587
|
deployment, independently of the role preset; no identity switching or token
|
|
574
588
|
borrowing is performed by coworker. Missing permission or uncertain publication
|
|
575
589
|
blocks successful integration handoff.
|
|
590
|
+
|
|
591
|
+
## Operational bootstrap roles
|
|
592
|
+
|
|
593
|
+
`bootstrap-worker` and `bootstrap-verifier` prepare and independently verify
|
|
594
|
+
a canonical project named explicitly in a lab task. Their evidence and
|
|
595
|
+
assignments remain in the lab task worktree; only the commissioned target
|
|
596
|
+
configuration may be accessed outside it. They preserve installed runtime
|
|
597
|
+
selection and session-scoped access. They never edit the overseer private
|
|
598
|
+
tree or start the project's overseer. Ordinary worker/reviewer roles retain
|
|
599
|
+
their product-worktree boundaries.
|
|
600
|
+
|
|
601
|
+
Prepare with `ace-coworker prepare --task <ref> --roles
|
|
602
|
+
bootstrap-worker,bootstrap-verifier --to <configured-owner>`. Preparation and
|
|
603
|
+
`ace-coworker start` do not launch a model process; the coordinator must launch
|
|
604
|
+
a separate agent with the returned brief and confirm its first turn.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coworker-bootstrap-verifier
|
|
3
|
+
description: Scoped operational bootstrap-verifier for a canonical project bootstrap
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
doc-type: workflow
|
|
6
|
+
title: bootstrap-verifier
|
|
7
|
+
purpose: Execute one lab-owned bootstrap assignment with explicit target scope.
|
|
8
|
+
---
|
|
9
|
+
# bootstrap-verifier
|
|
10
|
+
|
|
11
|
+
## Commission and scope
|
|
12
|
+
|
|
13
|
+
Read the prepared start config with `ace-coworker start --config <returned path>`.
|
|
14
|
+
Use its pinned assignment ID for every ace-assign operation. Read the executable
|
|
15
|
+
lab task and its explicit canonical target path, allowed configuration paths,
|
|
16
|
+
operations, runtime selection and acceptance criteria. Missing or ambiguous
|
|
17
|
+
scope is an error report, never a guessed directory or permission.
|
|
18
|
+
|
|
19
|
+
The assignment and evidence belong to the prepared lab task worktree. This
|
|
20
|
+
operational role may act on the explicitly commissioned canonical target
|
|
21
|
+
outside that worktree; this exception does not authorize other projects or
|
|
22
|
+
product implementation. Resolve target paths before effects and reject symlink
|
|
23
|
+
escapes outside the commissioned root. Preserve unrelated changes and secrets.
|
|
24
|
+
Never write `.ace-tasks/_overseer`; the coordinator alone owns its private tree.
|
|
25
|
+
|
|
26
|
+
Operational tools use the selected installed ACE closure, not target binstubs
|
|
27
|
+
or its development Gemfile. Record actual executable/gem/instruction paths.
|
|
28
|
+
Additional credentials or privileges are session-scoped through the existing
|
|
29
|
+
auth handoff; do not make permanent group grants or copy credentials into
|
|
30
|
+
project config, task evidence or prompts. Missing access is a report to the
|
|
31
|
+
coordinator, not permission to borrow an account or change ownership.
|
|
32
|
+
|
|
33
|
+
## Assignment and report
|
|
34
|
+
|
|
35
|
+
Drive the pinned ace-assign step through start/finish/fail. Store evidence in
|
|
36
|
+
the executable task's docs. Failed or unavailable required checks block success.
|
|
37
|
+
Use `ace-coworker report --config <returned path>` for the truthful assignment
|
|
38
|
+
outcome. A process exit, prepared config or printed CLI brief is not completion.
|
|
39
|
+
After interruption, read current state before repeating any external effect;
|
|
40
|
+
resume the same assignment, never silently create a replacement.
|
|
41
|
+
|
|
42
|
+
## Independent verification
|
|
43
|
+
|
|
44
|
+
Run as a separate agent from the worker. Read the worker evidence, then check
|
|
45
|
+
the actual target files and installed runtime independently. Verify requested
|
|
46
|
+
configuration, allowed-change boundaries, executable resolution and dependency
|
|
47
|
+
readiness with the task's explicit checks; compare actual results with the
|
|
48
|
+
worker's claims. Do not repair the target or accept your own preparation.
|
|
49
|
+
Report discrepancies as failure for the coordinator to return to the worker.
|
|
50
|
+
|
|
51
|
+
Do not start the project overseer: the coordinator owns the final reconcile,
|
|
52
|
+
first-turn and eyes acceptance. Your success accepts preparation only.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coworker-bootstrap-worker
|
|
3
|
+
description: Scoped operational bootstrap-worker for a canonical project bootstrap
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
doc-type: workflow
|
|
6
|
+
title: bootstrap-worker
|
|
7
|
+
purpose: Execute one lab-owned bootstrap assignment with explicit target scope.
|
|
8
|
+
---
|
|
9
|
+
# bootstrap-worker
|
|
10
|
+
|
|
11
|
+
## Commission and scope
|
|
12
|
+
|
|
13
|
+
Read the prepared start config with `ace-coworker start --config <returned path>`.
|
|
14
|
+
Use its pinned assignment ID for every ace-assign operation. Read the executable
|
|
15
|
+
lab task and its explicit canonical target path, allowed configuration paths,
|
|
16
|
+
operations, runtime selection and acceptance criteria. Missing or ambiguous
|
|
17
|
+
scope is an error report, never a guessed directory or permission.
|
|
18
|
+
|
|
19
|
+
The assignment and evidence belong to the prepared lab task worktree. This
|
|
20
|
+
operational role may act on the explicitly commissioned canonical target
|
|
21
|
+
outside that worktree; this exception does not authorize other projects or
|
|
22
|
+
product implementation. Resolve target paths before effects and reject symlink
|
|
23
|
+
escapes outside the commissioned root. Preserve unrelated changes and secrets.
|
|
24
|
+
Never write `.ace-tasks/_overseer`; the coordinator alone owns its private tree.
|
|
25
|
+
|
|
26
|
+
Operational tools use the selected installed ACE closure, not target binstubs
|
|
27
|
+
or its development Gemfile. Record actual executable/gem/instruction paths.
|
|
28
|
+
Additional credentials or privileges are session-scoped through the existing
|
|
29
|
+
auth handoff; do not make permanent group grants or copy credentials into
|
|
30
|
+
project config, task evidence or prompts. Missing access is a report to the
|
|
31
|
+
coordinator, not permission to borrow an account or change ownership.
|
|
32
|
+
|
|
33
|
+
## Assignment and report
|
|
34
|
+
|
|
35
|
+
Drive the pinned ace-assign step through start/finish/fail. Store evidence in
|
|
36
|
+
the executable task's docs. Failed or unavailable required checks block success.
|
|
37
|
+
Use `ace-coworker report --config <returned path>` for the truthful assignment
|
|
38
|
+
outcome. A process exit, prepared config or printed CLI brief is not completion.
|
|
39
|
+
After interruption, read current state before repeating any external effect;
|
|
40
|
+
resume the same assignment, never silently create a replacement.
|
|
41
|
+
|
|
42
|
+
## Prepare the target
|
|
43
|
+
|
|
44
|
+
Change only commissioned configuration and dependency installation paths.
|
|
45
|
+
Do not edit product code, replace tracked binstubs to bypass installed mode,
|
|
46
|
+
or rewrite existing project dependency declarations. A product/tool defect
|
|
47
|
+
requires a separate code-change commission. Use the existing configuration
|
|
48
|
+
and installation tools; do not invent a second configuration owner.
|
|
49
|
+
|
|
50
|
+
Verify the requested configuration and installed dependency readiness. Record
|
|
51
|
+
before/after state and exact checks without secrets. Do not start another
|
|
52
|
+
project overseer yourself: after independent verification the lab coordinator
|
|
53
|
+
owns reconcile/start. Leave unrelated work and live services untouched.
|
|
@@ -82,12 +82,16 @@ the exact candidate head. Otherwise WITHHOLD the merge and report/escalate.
|
|
|
82
82
|
3. **Evaluate the gate (deterministic).**
|
|
83
83
|
- `ace-coworker gate --candidate-head <sha> --review-head <sha>
|
|
84
84
|
--review-verdict accept|continue|escalate --tests executed,passed
|
|
85
|
-
--dep <leaf>=integrated --dep <leaf>=missing`
|
|
85
|
+
--tests-head <sha> --dep <leaf>=integrated --dep <leaf>=missing`
|
|
86
86
|
(repeat `--dep` per dependency; omit `--candidate-head`/`--review-head`
|
|
87
87
|
when genuinely unknown so the gate blocks on the missing evidence).
|
|
88
|
+
`--tests-head` is REQUIRED whenever test evidence is supplied: it is
|
|
89
|
+
the candidate head the executed test run covered, and the gate
|
|
90
|
+
blocks on stale test evidence without it.
|
|
88
91
|
- The gate (`Ace::Coworker::Atoms::IntegrationGate`) is pure: it returns
|
|
89
92
|
`ready` or `blocked` with per-check reasons (dependencies, candidate
|
|
90
|
-
drift, review freshness/verdict, executed+passing tests
|
|
93
|
+
drift, review freshness/verdict, executed+passing tests bound to the
|
|
94
|
+
tested head). `blocked` is a
|
|
91
95
|
legitimate outcome with exit 0; only invalid input fails the command.
|
|
92
96
|
- A candidate change after the review (candidate head != reviewed head)
|
|
93
97
|
invalidates the review: the gate reports a stale review even when the
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coworker-second-captain
|
|
3
|
+
description: Second Captain advisory coworker role — propose an answer with rationale and grounds into the exact HITL case; never answer in the human's name, never approve, never gate work
|
|
4
|
+
allowed-tools: Bash, Read
|
|
5
|
+
doc-type: workflow
|
|
6
|
+
title: Second Captain Workflow
|
|
7
|
+
purpose: Bind the advisory role's behavior: one marked suggestion per case/revision with rationale and grounds in the same HITL thread, non-blocking on delivery, discarded when the human answered first, excluded from secret cases.
|
|
8
|
+
ace-docs:
|
|
9
|
+
last-updated: '2026-10-30'
|
|
10
|
+
last-checked: '2026-10-30'
|
|
11
|
+
---
|
|
12
|
+
# Second Captain Workflow
|
|
13
|
+
|
|
14
|
+
## Goal
|
|
15
|
+
|
|
16
|
+
You are the Second Captain: an advisory coworker delegated for ONE HITL
|
|
17
|
+
case (task 8xs.t.pu0.b). You draft a proposed answer so the Captain sees a
|
|
18
|
+
marked suggestion with its reasoning in the same thread. You are an agent,
|
|
19
|
+
not a second human: you never answer in the Captain's name, never approve
|
|
20
|
+
or release gated work, and your suggestion is never treated as human
|
|
21
|
+
consent.
|
|
22
|
+
|
|
23
|
+
## Instructions
|
|
24
|
+
|
|
25
|
+
Run the loaded workflow as the source of truth and execute it end-to-end
|
|
26
|
+
instead of only summarizing it.
|
|
27
|
+
|
|
28
|
+
### 1) Read the exact case
|
|
29
|
+
|
|
30
|
+
Open the delegated case file. Work ONLY from the case content and the
|
|
31
|
+
grounds it references (task/assignment/report evidence). If the grounds are
|
|
32
|
+
insufficient for a defensible proposal, say so in the suggestion — never
|
|
33
|
+
fabricate precedent or confidence.
|
|
34
|
+
|
|
35
|
+
### 2) Learn from every real decision
|
|
36
|
+
|
|
37
|
+
When the Captain answers a case that carried your suggestion, compare the
|
|
38
|
+
decision with your proposal and write ONE lesson at that case (task
|
|
39
|
+
8xs.t.pu0.c):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ace-hitl lesson CASE_ID --by second-captain \
|
|
43
|
+
--relation accepted|rejected|modified \
|
|
44
|
+
--takeaway "what the next suggestion should learn"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
A case without your suggestion has NOTHING to compare — never fabricate
|
|
48
|
+
agreement. Identical reprocessing is a no-op. The lesson cites the exact
|
|
49
|
+
question/suggestion/decision revisions; it never overwrites them and never
|
|
50
|
+
changes the decision's author.
|
|
51
|
+
|
|
52
|
+
### 3) Ground the next suggestion in citable history
|
|
53
|
+
|
|
54
|
+
Before proposing, read the decision history available to THIS project
|
|
55
|
+
(`ace-hitl history`): answered, non-secret cases with their suggestions,
|
|
56
|
+
decisions and lessons. Cite the real case ids you relied on and note the
|
|
57
|
+
limits of the similarity; a NEWER explicit Captain correction outranks an
|
|
58
|
+
older suggestion. When you have no applicable precedent, SAY SO — a visible
|
|
59
|
+
lack of grounds is honest, a fabricated precedent is not. Secret/OTP values
|
|
60
|
+
never enter your proposals, takeaways, or citations.
|
|
61
|
+
|
|
62
|
+
### 4) Write the suggestion into the case
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ace-hitl suggest CASE_ID --by second-captain \
|
|
66
|
+
--text "proposed answer" \
|
|
67
|
+
--rationale "why this is the defensible choice — cite case ids you relied on" \
|
|
68
|
+
--refs task:8xs.t.pu0,assignment:job-7
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
One suggestion per case/revision; an identical repeat is a no-op. The
|
|
72
|
+
suggestion lands as its own marked section in the case — never as the
|
|
73
|
+
Answer.
|
|
74
|
+
|
|
75
|
+
### 5) Stop
|
|
76
|
+
|
|
77
|
+
Your assignment ends with the written suggestion. Do not wake the Captain,
|
|
78
|
+
do not open a new case, do not apply or await the answer.
|
|
79
|
+
|
|
80
|
+
## Boundaries
|
|
81
|
+
|
|
82
|
+
- A question marked `secret: true` (e.g. OTP) is NEVER delegated to you; if
|
|
83
|
+
you receive one, report the mismatch and stop.
|
|
84
|
+
- If the Captain already answered, DISCARD your late proposal, mark your
|
|
85
|
+
assignment complete, and do not notify anyone — the human decision stands
|
|
86
|
+
and needs no second approval.
|
|
87
|
+
- Your advisory rights cover reading the case and its referenced evidence
|
|
88
|
+
only — no merges, no releases, no token use.
|
|
@@ -52,6 +52,7 @@ module Ace
|
|
|
52
52
|
"task" => str(raw["task"]),
|
|
53
53
|
"assignment" => str(raw["assignment"]),
|
|
54
54
|
"overseer" => str(raw["overseer"]),
|
|
55
|
+
"case" => str(raw["case"]),
|
|
55
56
|
"reporting" => {"channel" => nested_str(raw, "reporting", "channel").empty? ? "hitl" : nested_str(raw, "reporting", "channel")},
|
|
56
57
|
"errors" => {"on_failure" => nested_str(raw, "errors", "on_failure").empty? ? "report" : nested_str(raw, "errors", "on_failure")}
|
|
57
58
|
}.compact
|
|
@@ -3,26 +3,39 @@
|
|
|
3
3
|
module Ace
|
|
4
4
|
module Coworker
|
|
5
5
|
module Atoms
|
|
6
|
-
# Pure pre-merge integration gate (8xg.t.sbz.4.3 / contract
|
|
7
|
-
# integrator merges only a candidate
|
|
8
|
-
# integrated predecessors, (b) current
|
|
9
|
-
# head (no drift), (c) tests were
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
6
|
+
# Pure pre-merge integration gate (8xg.t.sbz.4.3 / contract, HEAD
|
|
7
|
+
# binding per 8xs.t.pu0.8): the integrator merges only a candidate
|
|
8
|
+
# whose (a) dependencies are integrated predecessors, (b) current
|
|
9
|
+
# head matches the reviewed head (no drift), (c) tests were
|
|
10
|
+
# executed, passed, AND BOUND TO THE EXACT CANDIDATE HEAD (bare
|
|
11
|
+
# executed/passed without a head covers nothing), (d) a fresh
|
|
12
|
+
# independent review verdict accepts the EXACT candidate head, and
|
|
13
|
+
# (e) the formal approval — when required — also names this head
|
|
14
|
+
# and was given by a NAMED, DIFFERENT account than the author (an
|
|
15
|
+
# anonymous approval proves nothing). Any
|
|
16
|
+
# unknown or contradictory fact is a blocking reason - a code
|
|
17
|
+
# change or rebase after tests or review invalidates those bases
|
|
18
|
+
# for the old candidate; uncertainty must be verified against the
|
|
19
|
+
# real worktree/reports, never guessed or retried blind. Explicit
|
|
20
|
+
# :blocked outcome with reasons, never an exception. No IO, no
|
|
21
|
+
# writes, no merges: the gate decides readiness only; the role
|
|
22
|
+
# drives git/ace-git (the merge adapter's expected-head condition
|
|
23
|
+
# refuses a candidate that moved between gate and merge).
|
|
16
24
|
module IntegrationGate
|
|
17
25
|
ACCEPT_VERDICTS = %w[accept].freeze
|
|
18
26
|
|
|
19
27
|
# @param input [Hash] string-keyed facts:
|
|
20
28
|
# "candidate_head" => String (current head of the candidate)
|
|
21
29
|
# "review" => {"head" => String reviewed head, "verdict" => String}
|
|
22
|
-
# "tests" => {"executed" => bool, "passed" => bool
|
|
30
|
+
# "tests" => {"executed" => bool, "passed" => bool,
|
|
31
|
+
# "head" => String head the test run covered}
|
|
32
|
+
# "approval" => {"head" => String, "by" => String account} (a
|
|
33
|
+
# nil/empty approval skips the formal-approval check; lanes
|
|
34
|
+
# that require it must supply it)
|
|
35
|
+
# "author" => String candidate author account (optional)
|
|
23
36
|
# "dependencies" => {name => bool (integrated predecessor)}
|
|
24
37
|
# @return [Hash] {verdict: :ready | :blocked, reasons: [String],
|
|
25
|
-
# failed_checks: [:dependencies|:candidate|:review|:tests|:input]}
|
|
38
|
+
# failed_checks: [:dependencies|:candidate|:review|:tests|:approval|:input]}
|
|
26
39
|
def self.evaluate(input)
|
|
27
40
|
unless input.is_a?(Hash) && input.keys.all? { |k| k.is_a?(String) }
|
|
28
41
|
return {verdict: :blocked,
|
|
@@ -70,6 +83,40 @@ module Ace
|
|
|
70
83
|
reasons << "tests not passing: executed tests failed or their outcome is unknown"
|
|
71
84
|
failed << :tests
|
|
72
85
|
end
|
|
86
|
+
tests_head = str(tests["head"])
|
|
87
|
+
if tests_head.empty?
|
|
88
|
+
reasons << "test evidence not bound to a candidate head: executed/passed covers no " \
|
|
89
|
+
"verifiable candidate - re-run the tests on the current head and record it"
|
|
90
|
+
failed << :tests
|
|
91
|
+
elsif !candidate_head.empty? && tests_head.downcase != candidate_head.downcase
|
|
92
|
+
reasons << "stale test evidence: candidate #{candidate_head} is not the tested head #{tests_head}"
|
|
93
|
+
failed << :tests
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
approval = hash(input["approval"])
|
|
97
|
+
unless approval.empty?
|
|
98
|
+
approval_head = str(approval["head"])
|
|
99
|
+
approved_by = str(approval["by"])
|
|
100
|
+
if approval_head.empty?
|
|
101
|
+
reasons << "formal approval not bound to a candidate head: the approval covers no " \
|
|
102
|
+
"verifiable candidate"
|
|
103
|
+
failed << :approval
|
|
104
|
+
elsif !candidate_head.empty? && approval_head.downcase != candidate_head.downcase
|
|
105
|
+
reasons << "stale formal approval: candidate #{candidate_head} is not the approved " \
|
|
106
|
+
"head #{approval_head}"
|
|
107
|
+
failed << :approval
|
|
108
|
+
end
|
|
109
|
+
author = str(input["author"])
|
|
110
|
+
if approved_by.empty?
|
|
111
|
+
reasons << "formal approval is anonymous: no approving account is recorded — " \
|
|
112
|
+
"the author≠approver guarantee is vacuous; record the approving lane account"
|
|
113
|
+
failed << :approval
|
|
114
|
+
elsif !author.empty? && approved_by.downcase == author.downcase
|
|
115
|
+
reasons << "formal approval by the author's own account '#{approved_by}': the formal " \
|
|
116
|
+
"approver must be a different configured lane account"
|
|
117
|
+
failed << :approval
|
|
118
|
+
end
|
|
119
|
+
end
|
|
73
120
|
|
|
74
121
|
{verdict: reasons.empty? ? :ready : :blocked,
|
|
75
122
|
reasons: reasons, failed_checks: failed.uniq}
|
|
@@ -7,7 +7,9 @@ module Ace
|
|
|
7
7
|
# placeholders from a context hash; unknown placeholders stay literal.
|
|
8
8
|
# No IO.
|
|
9
9
|
class PromptTemplate
|
|
10
|
-
|
|
10
|
+
# `case` carries the HITL case id for per-case delegation roles
|
|
11
|
+
# (e.g. second-captain); roles without it simply never reference it.
|
|
12
|
+
PLACEHOLDERS = %w[task assignment role overseer case].freeze
|
|
11
13
|
PLACEHOLDER_PATTERN = /\{\{(#{PLACEHOLDERS.map { |p| Regexp.escape(p) }.join('|')})\}\}/.freeze
|
|
12
14
|
|
|
13
15
|
# @param template [String] preset start_prompt with {{placeholders}}
|
|
@@ -15,6 +15,7 @@ module Ace
|
|
|
15
15
|
option :task, desc: "Task reference that must resolve in this worktree (required)"
|
|
16
16
|
option :assignment, desc: "Assignment id pinned to the role (required)"
|
|
17
17
|
option :overseer, desc: "Overseer reporting address (required)"
|
|
18
|
+
option :"hitl-case", desc: "HITL case id for per-case delegation roles (renders the preset's {{case}})"
|
|
18
19
|
option :"start-prompt", desc: "Literal start prompt overriding the preset template"
|
|
19
20
|
option :config, desc: "Config path (default from cascade: .ace-local/coworker/config.yml)"
|
|
20
21
|
option :force, type: :boolean, default: false, desc: "Allow overwriting an existing config"
|
|
@@ -47,7 +48,7 @@ module Ace
|
|
|
47
48
|
orchestrator = @orchestrator || build_orchestrator(options[:config])
|
|
48
49
|
result = orchestrator.call(
|
|
49
50
|
role: role, task: task, assignment: assignment, overseer: overseer,
|
|
50
|
-
start_prompt: options[:"start-prompt"],
|
|
51
|
+
start_prompt: options[:"start-prompt"], hitl_case: options[:"hitl-case"],
|
|
51
52
|
force: options[:force] == true, dry_run: options[:"dry-run"] == true
|
|
52
53
|
)
|
|
53
54
|
|
|
@@ -13,26 +13,34 @@ module Ace
|
|
|
13
13
|
|
|
14
14
|
example [
|
|
15
15
|
"gate --candidate-head 1a2b3c4 --review-head 1a2b3c4 --review-verdict accept \\",
|
|
16
|
-
" --tests executed,passed --dep 8xg.t.sbz.4.2=integrated",
|
|
16
|
+
" --tests executed,passed --tests-head 1a2b3c4 --dep 8xg.t.sbz.4.2=integrated \\",
|
|
17
|
+
" --approval-head 1a2b3c4 --approval-by lab-merge-ace --author lab-overseer",
|
|
17
18
|
"gate --candidate-head 1a2b3c4 --review-head 0d0e0f --review-verdict accept \\",
|
|
18
|
-
" --tests executed,passed --dep 8xg.t.sbz.4.2=missing"
|
|
19
|
+
" --tests executed,passed --tests-head 1a2b3c4 --dep 8xg.t.sbz.4.2=missing"
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
option :candidate_head, desc: "Current head of the candidate branch (omit when unknown)"
|
|
22
23
|
option :review_head, desc: "Candidate head the review verdict covers"
|
|
23
24
|
option :review_verdict, required: true, desc: "Independent review verdict (accept, continue, escalate)"
|
|
24
25
|
option :tests, type: :array, default: [], desc: "Test evidence flags: executed, passed"
|
|
26
|
+
option :tests_head, desc: "Candidate head the executed test run covered (required with test evidence)"
|
|
27
|
+
option :approval_head, desc: "Candidate head the formal approval covers (lanes requiring formal approval)"
|
|
28
|
+
option :approval_by, desc: "Account that gave the formal approval"
|
|
29
|
+
option :author, desc: "Candidate author account (the formal approver must differ)"
|
|
25
30
|
option :dep, type: :array, default: [], desc: "Dependency states as name=integrated|missing pairs"
|
|
26
31
|
option :format, default: "table", desc: "Output format (table, json)"
|
|
27
32
|
option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress non-essential output"
|
|
28
33
|
option :debug, aliases: ["-d"], type: :boolean, default: false, desc: "Show debug output"
|
|
29
34
|
|
|
30
|
-
def call(candidate_head: nil, review_head: nil, review_verdict: nil, tests: [],
|
|
31
|
-
|
|
35
|
+
def call(candidate_head: nil, review_head: nil, review_verdict: nil, tests: [],
|
|
36
|
+
tests_head: nil, approval_head: nil, approval_by: nil, author: nil, dep: [],
|
|
37
|
+
format: "table", **options)
|
|
32
38
|
result = Atoms::IntegrationGate.evaluate(
|
|
33
39
|
"candidate_head" => candidate_head.to_s,
|
|
34
40
|
"review" => {"head" => review_head.to_s, "verdict" => review_verdict.to_s},
|
|
35
|
-
"tests" => tests_flags(tests),
|
|
41
|
+
"tests" => tests_flags(tests).merge("head" => tests_head.to_s),
|
|
42
|
+
"approval" => approval_for(approval_head, approval_by),
|
|
43
|
+
"author" => author.to_s,
|
|
36
44
|
"dependencies" => dependency_states(dep)
|
|
37
45
|
)
|
|
38
46
|
|
|
@@ -47,6 +55,14 @@ module Ace
|
|
|
47
55
|
|
|
48
56
|
private
|
|
49
57
|
|
|
58
|
+
# A formal approval participates only when the lane supplied
|
|
59
|
+
# approval evidence; omitted approval facts skip the check.
|
|
60
|
+
def approval_for(approval_head, approval_by)
|
|
61
|
+
return {} if approval_head.to_s.strip.empty? && approval_by.to_s.strip.empty?
|
|
62
|
+
|
|
63
|
+
{"head" => approval_head.to_s, "by" => approval_by.to_s}
|
|
64
|
+
end
|
|
65
|
+
|
|
50
66
|
def tests_flags(tests)
|
|
51
67
|
flags = Array(tests).flat_map { |value| value.to_s.split(",") }.map { |f| f.strip.downcase }.reject(&:empty?)
|
|
52
68
|
flags.each do |flag|
|
|
@@ -56,7 +56,8 @@ module Ace
|
|
|
56
56
|
# @raise [Error] on unknown role, identity mismatch, invalid
|
|
57
57
|
# assembly, a refused overwrite, a config path escaping the
|
|
58
58
|
# project root, or a directory config target
|
|
59
|
-
def call(role:, task:, assignment:, overseer:, start_prompt: nil,
|
|
59
|
+
def call(role:, task:, assignment:, overseer:, start_prompt: nil, hitl_case: nil,
|
|
60
|
+
force: false, dry_run: false)
|
|
60
61
|
preset = @preset_loader.fetch(role)
|
|
61
62
|
|
|
62
63
|
# Canonicalize the task identity first: the assignment match and
|
|
@@ -69,10 +70,17 @@ module Ace
|
|
|
69
70
|
canonical_task = resolved.id.to_s
|
|
70
71
|
@assignment_metadata.verify_task_match!(assignment, canonical_task)
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
hitl_case = hitl_case.to_s.strip
|
|
74
|
+
if start_prompt.to_s.strip.empty? && preset["start_prompt"].to_s.include?("{{case}}") && hitl_case.empty?
|
|
75
|
+
raise Error,
|
|
76
|
+
"the '#{role}' start_prompt delegates to a HITL case ({{case}}); " \
|
|
77
|
+
"pass the exact case id (--hitl-case CASE_ID) or a literal --start-prompt"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
prompt = start_prompt.to_s.strip.empty? ? render_prompt(preset, role, canonical_task, assignment, overseer, hitl_case) : start_prompt
|
|
73
81
|
|
|
74
82
|
config = build_config(preset, role: role, task: canonical_task, assignment: assignment,
|
|
75
|
-
overseer: overseer, prompt: prompt)
|
|
83
|
+
overseer: overseer, prompt: prompt, hitl_case: hitl_case)
|
|
76
84
|
errors = Atoms::ConfigSchema.errors(config)
|
|
77
85
|
unless errors.empty?
|
|
78
86
|
raise Error, "commissioned config is invalid: #{errors.join('; ')}"
|
|
@@ -91,12 +99,13 @@ module Ace
|
|
|
91
99
|
|
|
92
100
|
private
|
|
93
101
|
|
|
94
|
-
def render_prompt(preset, role, task, assignment, overseer)
|
|
102
|
+
def render_prompt(preset, role, task, assignment, overseer, hitl_case)
|
|
95
103
|
Atoms::PromptTemplate.render(preset["start_prompt"],
|
|
96
|
-
{"task" => task, "assignment" => assignment, "role" => role,
|
|
104
|
+
{"task" => task, "assignment" => assignment, "role" => role,
|
|
105
|
+
"overseer" => overseer, "case" => hitl_case})
|
|
97
106
|
end
|
|
98
107
|
|
|
99
|
-
def build_config(preset, role:, task:, assignment:, overseer:, prompt:)
|
|
108
|
+
def build_config(preset, role:, task:, assignment:, overseer:, prompt:, hitl_case: "")
|
|
100
109
|
config = {
|
|
101
110
|
"role" => role,
|
|
102
111
|
"instructions" => preset["instructions"],
|
|
@@ -105,6 +114,7 @@ module Ace
|
|
|
105
114
|
"assignment" => assignment,
|
|
106
115
|
"overseer" => overseer
|
|
107
116
|
}
|
|
117
|
+
config["case"] = hitl_case unless hitl_case.empty?
|
|
108
118
|
config["toolchain"] = "installed" if Ace::Support::Cli::Toolchain.installed?
|
|
109
119
|
config["reporting"] = {"channel" => preset["reporting"]} unless preset["reporting"].to_s.empty?
|
|
110
120
|
config["errors"] = {"on_failure" => preset["errors"]} unless preset["errors"].to_s.empty?
|
data/lib/ace/coworker/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-coworker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-31 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-support-cli
|
|
@@ -234,10 +234,15 @@ extensions: []
|
|
|
234
234
|
extra_rdoc_files: []
|
|
235
235
|
files:
|
|
236
236
|
- ".ace-defaults/coworker/config.yml"
|
|
237
|
+
- ".ace-defaults/coworker/roles/bootstrap-verifier.yml"
|
|
238
|
+
- ".ace-defaults/coworker/roles/bootstrap-worker.yml"
|
|
237
239
|
- ".ace-defaults/coworker/roles/integrator.yml"
|
|
238
240
|
- ".ace-defaults/coworker/roles/reviewer.yml"
|
|
241
|
+
- ".ace-defaults/coworker/roles/second-captain.yml"
|
|
239
242
|
- ".ace-defaults/coworker/roles/spec.yml"
|
|
240
243
|
- ".ace-defaults/coworker/roles/worker.yml"
|
|
244
|
+
- ".ace-defaults/coworker/sequences/bootstrap-verifier.yml"
|
|
245
|
+
- ".ace-defaults/coworker/sequences/bootstrap-worker.yml"
|
|
241
246
|
- ".ace-defaults/coworker/sequences/integrator.yml"
|
|
242
247
|
- ".ace-defaults/coworker/sequences/reviewer.yml"
|
|
243
248
|
- ".ace-defaults/coworker/sequences/spec.yml"
|
|
@@ -248,8 +253,11 @@ files:
|
|
|
248
253
|
- Rakefile
|
|
249
254
|
- docs/usage.md
|
|
250
255
|
- exe/ace-coworker
|
|
256
|
+
- handbook/workflow-instructions/coworker/bootstrap-verifier.wf.md
|
|
257
|
+
- handbook/workflow-instructions/coworker/bootstrap-worker.wf.md
|
|
251
258
|
- handbook/workflow-instructions/coworker/integrator.wf.md
|
|
252
259
|
- handbook/workflow-instructions/coworker/reviewer.wf.md
|
|
260
|
+
- handbook/workflow-instructions/coworker/second-captain.wf.md
|
|
253
261
|
- handbook/workflow-instructions/coworker/spec.wf.md
|
|
254
262
|
- handbook/workflow-instructions/coworker/worker.wf.md
|
|
255
263
|
- lib/ace/coworker.rb
|