@syntax-syllogism/aloop 0.5.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.
- package/CHANGELOG.md +141 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/bin/loop.mjs +90 -0
- package/package.json +46 -0
- package/presets/work-item/README.md +31 -0
- package/presets/work-item/loop.config.mjs +13 -0
- package/presets/work-item/prompts/address.md +57 -0
- package/presets/work-item/prompts/docs.md +31 -0
- package/presets/work-item/prompts/git.md +44 -0
- package/presets/work-item/prompts/implement.md +50 -0
- package/presets/work-item/prompts/review.md +77 -0
- package/prompts/address.md +59 -0
- package/prompts/docs.md +23 -0
- package/prompts/git.md +29 -0
- package/prompts/implement.md +45 -0
- package/prompts/review.md +74 -0
- package/src/adapters.mjs +281 -0
- package/src/command.mjs +65 -0
- package/src/config.mjs +175 -0
- package/src/entrypoint.mjs +22 -0
- package/src/git.mjs +91 -0
- package/src/index.mjs +6 -0
- package/src/pipeline.mjs +813 -0
- package/src/prompts.mjs +54 -0
- package/src/state.mjs +88 -0
- package/src/verdict.mjs +69 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
|
|
7
|
+
|
|
8
|
+
## [0.5.0] - 2026-09-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Config-registered engine adapters for customizing loop execution environments
|
|
13
|
+
- Worktree setup with automatic no-op detection
|
|
14
|
+
- Lean prompts and work-item preset templates
|
|
15
|
+
- Optional task input parameter to decouple from work-item operations
|
|
16
|
+
- Complete configuration overrides for flexible behavior customization
|
|
17
|
+
- Audited resume engine overrides for workflow control
|
|
18
|
+
- Configurable base branch support for multi-branch operations
|
|
19
|
+
- Per-phase commits with configurable AI model and effort levels
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Standalone public package history export
|
|
24
|
+
- Task context inclusion in AI review prompts
|
|
25
|
+
- Piped input safety with explicit confirmation requirements
|
|
26
|
+
- Worktree stability on dirty git states
|
|
27
|
+
- Wiki commit preservation with cron scheduling
|
|
28
|
+
- Output streaming for long-running phases to prevent false hang detection
|
|
29
|
+
|
|
30
|
+
## [Unreleased]
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Pre-extraction history
|
|
35
|
+
|
|
36
|
+
History from before the standalone extraction (changesets format), preserved for reference.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## 0.4.6
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 1eac189: Fix the `agy` engine adapter so it works in the loop's headless runs. Pass
|
|
44
|
+
`--dangerously-skip-permissions` — agy has no non-interactive `auto` permission
|
|
45
|
+
mode, so without it agy auto-denies the first command tool and exits 0 having
|
|
46
|
+
done nothing, and the phase is wrongly marked complete. Also switch agy to
|
|
47
|
+
`--output-format stream-json` with a renderer for its `init`/`step_update`/
|
|
48
|
+
`result` events, so a multi-minute phase streams readable progress instead of
|
|
49
|
+
buffering every byte until exit and looking like a hang.
|
|
50
|
+
|
|
51
|
+
## 0.4.5
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- 35b961b: Stall the git phase deterministically when the worktree is dirty.
|
|
56
|
+
|
|
57
|
+
The `git` phase pushes and opens a PR and is forbidden from committing, yet it ran as an unbounded agent. When an earlier phase left the tree dirty, the agent — told the tree was already clean — improvised an uncommittable "fix" and spun until its per-command timeout. The runner now asserts a clean worktree before any phase flagged `requiresCleanTree` (the built-in `git` phase) and stalls with the offending paths instead, and the git prompt tells the agent to stop and report rather than reconcile a dirty tree. The check is worktree cleanliness only: unresolved review findings deliberately do not block, so a clean tree with open findings can still be resumed through `docs` and `git`.
|
|
58
|
+
|
|
59
|
+
## 0.4.4
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- c522a34: Allow `aloop --config <path>` to load an external loop configuration,
|
|
64
|
+
including as a complete configuration override when resuming a run.
|
|
65
|
+
- c88fce3: Stop asking agents to commit wiki work items, move new work items to `IN PROGRESS`
|
|
66
|
+
at the start of implementation, and constrain loop status instructions to the
|
|
67
|
+
supported `TODO`, `IN PROGRESS`, `UNDER REVIEW`, and `DONE` values.
|
|
68
|
+
|
|
69
|
+
## 0.4.3
|
|
70
|
+
|
|
71
|
+
### Patch Changes
|
|
72
|
+
|
|
73
|
+
- a5540e2: Allow `aloop --config <path>` to load an external loop configuration,
|
|
74
|
+
including as a complete configuration override when resuming a run.
|
|
75
|
+
- 0b74814: Checkpoint the owed repair when a review hits the round cap.
|
|
76
|
+
|
|
77
|
+
Previously, a `CHANGES_REQUESTED` verdict on the final allowed round was not recorded as a pending repair, so the last review's findings were left unaddressed with no checkpoint. Resuming with a raised `--max-rounds` then started with a fresh review of the identical tree instead of running the `address` phase, burning a review round re-discovering the same findings. The repair is now checkpointed at the cap, so a resume runs the owed `address` phase before re-reviewing. Resuming without raising the cap stays a clean no-op.
|
|
78
|
+
|
|
79
|
+
- 4800fb5: Add an explicit `--override-engine` option to move a resumed run to a different
|
|
80
|
+
agent executable while recording the change in run state and phase logs.
|
|
81
|
+
|
|
82
|
+
## 0.4.2
|
|
83
|
+
|
|
84
|
+
### Patch Changes
|
|
85
|
+
|
|
86
|
+
- 97de439: Checkpoint the owed repair when a review hits the round cap.
|
|
87
|
+
|
|
88
|
+
Previously, a `CHANGES_REQUESTED` verdict on the final allowed round was not recorded as a pending repair, so the last review's findings were left unaddressed with no checkpoint. Resuming with a raised `--max-rounds` then started with a fresh review of the identical tree instead of running the `address` phase, burning a review round re-discovering the same findings. The repair is now checkpointed at the cap, so a resume runs the owed `address` phase before re-reviewing. Resuming without raising the cap stays a clean no-op.
|
|
89
|
+
|
|
90
|
+
## 0.4.1
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- a091002: Stop Claude phases from stalling silently.
|
|
95
|
+
|
|
96
|
+
- Run the Claude engine in `auto` permission mode instead of `acceptEdits`. A non-interactive `claude -p` run has nobody to answer a permission prompt, so under `acceptEdits` every Bash call was denied and the implement, gate-repair, docs, and git phases could not build, test, or commit.
|
|
97
|
+
- Ask Claude for `stream-json` output and render it to readable progress lines. `--output-format text` withheld every byte until the process exited, so a phase that ran for half an hour was indistinguishable from one that had hung.
|
|
98
|
+
- Raise the default per-command timeout from 30 to 60 minutes; a real implement phase routinely runs past the old cap and was killed mid-edit.
|
|
99
|
+
|
|
100
|
+
## 0.4.0
|
|
101
|
+
|
|
102
|
+
### Minor Changes
|
|
103
|
+
|
|
104
|
+
- 8f2421f: Add `--base-branch` to build and PR a run on top of another branch, for stacked PRs.
|
|
105
|
+
|
|
106
|
+
## 0.3.0
|
|
107
|
+
|
|
108
|
+
### Minor Changes
|
|
109
|
+
|
|
110
|
+
- 903d17c: Allow loop engine configuration to select an optional model and reasoning effort
|
|
111
|
+
per phase, preserve those effective settings when a run resumes, and display
|
|
112
|
+
them in dry-run output and phase logs. Existing string-based engine settings
|
|
113
|
+
remain supported.
|
|
114
|
+
- 903d17c: Commit implementation, repair, and documentation phases independently and use
|
|
115
|
+
review commit SHAs to resume incremental verdict rounds.
|
|
116
|
+
|
|
117
|
+
## 0.2.0
|
|
118
|
+
|
|
119
|
+
### Minor Changes
|
|
120
|
+
|
|
121
|
+
- 3eb19c2: Add `@syntax-syllogism/aloop`, an engine-agnostic agentic loop runner.
|
|
122
|
+
|
|
123
|
+
`aloop` drives a work item through implementation, a deterministic gate, a
|
|
124
|
+
capped review/repair loop, a documentation pass, and the git workflow, stopping
|
|
125
|
+
at an open pull request. Control flow, iteration caps, and exit conditions live
|
|
126
|
+
in the driver; agents only supply judgment.
|
|
127
|
+
|
|
128
|
+
- Engine adapters for `claude`, `codex`, and `agy`, selectable per phase, so the
|
|
129
|
+
reviewer can run on a different model family than the implementer.
|
|
130
|
+
- Phases are declared as a flat list and folded into a loop: a verdict phase
|
|
131
|
+
absorbs the repair phases after it and the gate before it.
|
|
132
|
+
- The review phase emits a machine-readable verdict. Parsing fails closed, and
|
|
133
|
+
the loop will not exit on approval while the gate re-check is red.
|
|
134
|
+
- Runs are isolated in a `git worktree`, with logs, verdicts, and resumable
|
|
135
|
+
state under `.loop/runs/<slug>/`.
|
|
136
|
+
- Only the `git` phase commits; earlier phases leave work uncommitted in the
|
|
137
|
+
worktree, so the reviewer reads the working tree rather than a branch range.
|
|
138
|
+
- `remote` selects the push target and is validated before the run starts,
|
|
139
|
+
rather than assuming `origin` in repos with several remotes.
|
|
140
|
+
- Prompts ship with the package and are overridable per phase from
|
|
141
|
+
`.loop/prompts/` in the consuming project.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jacob Richter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# aloop
|
|
2
|
+
|
|
3
|
+
`@syntax-syllogism/aloop` is an engine-agnostic agentic loop runner. It drives
|
|
4
|
+
a task through file-based implementation, deterministic checks, review, repair,
|
|
5
|
+
documentation, and git phases. The driver owns control flow; configured agent
|
|
6
|
+
CLIs provide judgment in fresh processes.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install --global @syntax-syllogism/aloop
|
|
12
|
+
# or run without a global install
|
|
13
|
+
npx @syntax-syllogism/aloop --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The package is published to the public npm registry and needs no private
|
|
17
|
+
registry configuration.
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
From a git repository with a `loop.config.mjs` (or with the defaults):
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
aloop --task "Add request tracing" --name request-tracing
|
|
25
|
+
aloop --task-file plan.md
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Inspect the rendered plan first with `aloop --task "..." --name example
|
|
29
|
+
--dry-run`. A terminal run asks for confirmation before each phase. Use `-y`
|
|
30
|
+
only after the configured engines and workflow have been proven for the task
|
|
31
|
+
shapes you intend to automate.
|
|
32
|
+
|
|
33
|
+
## How the loop works
|
|
34
|
+
|
|
35
|
+
The default pipeline is:
|
|
36
|
+
|
|
37
|
+
1. `implement` — make the requested change in an isolated git worktree.
|
|
38
|
+
2. `gate` — run deterministic commands such as `npm test`.
|
|
39
|
+
3. `review` — write a machine-readable verdict JSON file.
|
|
40
|
+
4. `address` — repair blocking findings, then repeat the gate and review up to
|
|
41
|
+
the configured round limit.
|
|
42
|
+
5. `docs` — update documentation when the implementation requires it.
|
|
43
|
+
6. `git` — verify the tree and prepare the branch for an open pull request.
|
|
44
|
+
|
|
45
|
+
Phases communicate through files rather than shared agent sessions. A review
|
|
46
|
+
verdict has the shape `{ verdict, summary, blocking, nits }`; malformed verdicts
|
|
47
|
+
fail closed. The runner never merges a branch and never treats an agent's prose
|
|
48
|
+
as a deterministic test result. See [`docs/loop.md`](docs/loop.md) for the
|
|
49
|
+
complete guide and verdict contract.
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Create `loop.config.mjs` in the repository being operated on:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
export default {
|
|
57
|
+
remote: 'origin',
|
|
58
|
+
engines: {
|
|
59
|
+
default: { name: 'claude', effort: 'high' },
|
|
60
|
+
review: { name: 'codex', effort: 'high' },
|
|
61
|
+
},
|
|
62
|
+
phases: ['implement', 'gate', 'review', 'address', 'docs', 'git'],
|
|
63
|
+
gate: ['npm test'],
|
|
64
|
+
setup: ['npm ci'],
|
|
65
|
+
maxRounds: 3,
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Supported built-in engines are `claude`, `codex`, and `agy`. The corresponding
|
|
70
|
+
CLI must already be installed and authenticated. Engine descriptors may include
|
|
71
|
+
an engine-specific `model` and `effort`. `--config` selects a configuration
|
|
72
|
+
file outside the current repository; command-line phase and round options take
|
|
73
|
+
precedence.
|
|
74
|
+
|
|
75
|
+
### Bring your own engine
|
|
76
|
+
|
|
77
|
+
Register an adapter under `adapters` when another CLI should run a phase. Its
|
|
78
|
+
`command({ prompt, cwd, addDirs, agent })` function returns `{ command, args }`.
|
|
79
|
+
It may also provide `efforts` validation and `createRenderer()` for streaming
|
|
80
|
+
output. Because adapters run commands with write access, non-interactive or
|
|
81
|
+
auto-approve flags can allow an agent to change files without asking. Review
|
|
82
|
+
the adapter and its permissions before enabling unattended runs.
|
|
83
|
+
|
|
84
|
+
## Prompt overrides and the work-item preset
|
|
85
|
+
|
|
86
|
+
Copy a phase prompt to `.loop/prompts/<phase>.md` to override only that phase.
|
|
87
|
+
Templates use the variables documented in `docs/loop.md` and fail if a
|
|
88
|
+
placeholder is unresolved.
|
|
89
|
+
|
|
90
|
+
For repositories using Markdown work items, install the bundled preset:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
mkdir -p .loop/prompts
|
|
94
|
+
cp -r node_modules/@syntax-syllogism/aloop/presets/work-item/prompts/. .loop/prompts/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The preset includes prompts and a sample configuration. Adapt it to the
|
|
98
|
+
repository's branches and gates before use.
|
|
99
|
+
|
|
100
|
+
## Building up to unattended runs
|
|
101
|
+
|
|
102
|
+
Use this progression:
|
|
103
|
+
|
|
104
|
+
1. Render prompts with `--dry-run`.
|
|
105
|
+
2. Watch one representative task through every phase.
|
|
106
|
+
3. Exercise the review loop with `--max-rounds 2`.
|
|
107
|
+
4. Add `-y` only for task shapes whose behavior is already understood.
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
npm ci
|
|
113
|
+
npm test
|
|
114
|
+
npm pack --dry-run
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Contributing
|
|
118
|
+
|
|
119
|
+
Issues and contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and
|
|
120
|
+
the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
121
|
+
|
|
122
|
+
## Security
|
|
123
|
+
|
|
124
|
+
See [SECURITY.md](SECURITY.md) for how to report vulnerabilities.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
[MIT](LICENSE) © Jacob Richter
|
package/bin/loop.mjs
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from 'node:util';
|
|
4
|
+
import { isMainEntrypoint } from '../src/entrypoint.mjs';
|
|
5
|
+
import { runLoop } from '../src/pipeline.mjs';
|
|
6
|
+
|
|
7
|
+
export function parseLoopArgs(argv) {
|
|
8
|
+
const { values } = parseArgs({
|
|
9
|
+
args: argv,
|
|
10
|
+
options: {
|
|
11
|
+
task: { type: 'string', short: 't' },
|
|
12
|
+
'task-file': { type: 'string', short: 'f' },
|
|
13
|
+
name: { type: 'string', short: 'n' },
|
|
14
|
+
branch: { type: 'string', short: 'b' },
|
|
15
|
+
'base-branch': { type: 'string' },
|
|
16
|
+
engine: { type: 'string', short: 'e' },
|
|
17
|
+
'override-engine': { type: 'boolean' },
|
|
18
|
+
config: { type: 'string' },
|
|
19
|
+
phases: { type: 'string' },
|
|
20
|
+
'max-rounds': { type: 'string' },
|
|
21
|
+
from: { type: 'string' },
|
|
22
|
+
resume: { type: 'boolean' },
|
|
23
|
+
yes: { type: 'boolean', short: 'y' },
|
|
24
|
+
'no-worktree': { type: 'boolean' },
|
|
25
|
+
'dry-run': { type: 'boolean' },
|
|
26
|
+
help: { type: 'boolean', short: 'h' },
|
|
27
|
+
},
|
|
28
|
+
allowPositionals: false,
|
|
29
|
+
strict: true,
|
|
30
|
+
});
|
|
31
|
+
if (values.help) return { help: true };
|
|
32
|
+
const maxRounds = values['max-rounds'] ? Number(values['max-rounds']) : undefined;
|
|
33
|
+
if (maxRounds !== undefined && (!Number.isInteger(maxRounds) || maxRounds < 1)) {
|
|
34
|
+
throw new Error('--max-rounds must be a positive integer');
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
task: values.task,
|
|
38
|
+
taskFile: values['task-file'],
|
|
39
|
+
name: values.name,
|
|
40
|
+
branch: values.branch,
|
|
41
|
+
baseBranch: values['base-branch'],
|
|
42
|
+
engine: values.engine,
|
|
43
|
+
overrideEngine: values['override-engine'],
|
|
44
|
+
config: values.config,
|
|
45
|
+
phases: values.phases ? values.phases.split(',').map((phase) => phase.trim()).filter(Boolean) : undefined,
|
|
46
|
+
maxRounds,
|
|
47
|
+
from: values.from,
|
|
48
|
+
resume: values.resume,
|
|
49
|
+
yes: values.yes,
|
|
50
|
+
noWorktree: values['no-worktree'],
|
|
51
|
+
dryRun: values['dry-run'],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function usage() {
|
|
56
|
+
return [
|
|
57
|
+
'Usage: aloop [options]',
|
|
58
|
+
'',
|
|
59
|
+
' -t, --task <text> Inline task description',
|
|
60
|
+
' -f, --task-file <path> Path to a task/plan/spec file',
|
|
61
|
+
' -n, --name <slug> Explicit run identity/slug',
|
|
62
|
+
' -b, --branch <name> Branch to build on (default: <branchPrefix><name>)',
|
|
63
|
+
' --base-branch <branch> Base to branch from and PR against (default: baseBranch config)',
|
|
64
|
+
' -e, --engine <name> Default engine: claude | codex | agy',
|
|
65
|
+
' --override-engine With --resume and --engine, replace saved agent executables',
|
|
66
|
+
' --config <path> Load loop configuration from this file (also overrides saved config on resume)',
|
|
67
|
+
' --phases a,b,c Override the configured phase list',
|
|
68
|
+
' --max-rounds <n> Cap on review/repair rounds',
|
|
69
|
+
' --from <phase> Start at this phase',
|
|
70
|
+
' --resume Skip phases already recorded complete',
|
|
71
|
+
' -y, --yes Run unattended (no per-phase confirmation; required without a terminal)',
|
|
72
|
+
' --no-worktree Work in the current checkout instead of a worktree',
|
|
73
|
+
' --dry-run Print the plan and rendered prompts, run nothing',
|
|
74
|
+
].join('\n');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isMainEntrypoint(import.meta.url)) {
|
|
78
|
+
try {
|
|
79
|
+
const args = parseLoopArgs(process.argv.slice(2));
|
|
80
|
+
if (args.help) {
|
|
81
|
+
console.log(usage());
|
|
82
|
+
} else {
|
|
83
|
+
await runLoop({ args });
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(error.message);
|
|
87
|
+
if (!error.command) console.error(usage());
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@syntax-syllogism/aloop",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Syntax & Syllogism agentic loop runner.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"aloop": "bin/loop.mjs"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin",
|
|
14
|
+
"src",
|
|
15
|
+
"prompts",
|
|
16
|
+
"presets",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"agentic",
|
|
23
|
+
"loop",
|
|
24
|
+
"code-review",
|
|
25
|
+
"claude",
|
|
26
|
+
"codex",
|
|
27
|
+
"antigravity",
|
|
28
|
+
"opencode",
|
|
29
|
+
"cli"
|
|
30
|
+
],
|
|
31
|
+
"homepage": "https://github.com/Syntax-Syllogism/aloop#readme",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/Syntax-Syllogism/aloop/issues"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/Syntax-Syllogism/aloop.git"
|
|
38
|
+
},
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "node --test"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Work-item preset
|
|
2
|
+
|
|
3
|
+
The default loop prompts are task-oriented and do not require a particular
|
|
4
|
+
document layout. This preset is for repositories that use the Syntax &
|
|
5
|
+
Syllogism work-item workflow.
|
|
6
|
+
|
|
7
|
+
## Assumptions
|
|
8
|
+
|
|
9
|
+
The preset expects:
|
|
10
|
+
|
|
11
|
+
- a Markdown task file with status frontmatter and `## Changelog` and
|
|
12
|
+
`## Code Review` sections;
|
|
13
|
+
- a separate repository for those task files; and
|
|
14
|
+
- a separate job or cron workflow that commits task-file changes.
|
|
15
|
+
|
|
16
|
+
The preset also includes an example `loop.config.mjs` with the owner's standard
|
|
17
|
+
branches, engines, phases, and `npm test` gate. Adjust it for your repository.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Install the package, create `.loop/prompts/`, and copy the preset prompts into
|
|
22
|
+
the project override directory:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
mkdir -p .loop/prompts
|
|
26
|
+
cp -r node_modules/@syntax-syllogism/aloop/presets/work-item/prompts/. .loop/prompts/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The runner loads project prompt overrides before its packaged defaults. Keep the
|
|
30
|
+
sample config as a starting point for `loop.config.mjs` if its settings match
|
|
31
|
+
your repository.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
baseBranch: 'master',
|
|
3
|
+
branchPrefix: 'feat/',
|
|
4
|
+
remote: 'origin',
|
|
5
|
+
engines: {
|
|
6
|
+
default: { name: 'claude', effort: 'high' },
|
|
7
|
+
review: { name: 'codex', effort: 'high' },
|
|
8
|
+
},
|
|
9
|
+
phases: ['implement', 'gate', 'review', 'address', 'docs', 'git'],
|
|
10
|
+
gate: ['npm test'],
|
|
11
|
+
maxRounds: 3,
|
|
12
|
+
timeoutMs: 30 * 60 * 1000,
|
|
13
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
A code review has been appended for task `{{TASK_NAME}}`. Please
|
|
2
|
+
address all findings, and if a task file is present (`{{TASK_FILE}}`), update its changelog.
|
|
3
|
+
|
|
4
|
+
The work is in the worktree at `{{REPO}}` on branch `{{BRANCH}}`; prior phases
|
|
5
|
+
have committed their changes.
|
|
6
|
+
|
|
7
|
+
This is round {{ROUND}} of at most {{MAX_ROUNDS}}. If the findings are not
|
|
8
|
+
resolved by round {{MAX_ROUNDS}} the run stops and a human picks it up, so fix
|
|
9
|
+
causes rather than symptoms.
|
|
10
|
+
|
|
11
|
+
## Blocking findings
|
|
12
|
+
|
|
13
|
+
{{FINDINGS}}
|
|
14
|
+
|
|
15
|
+
The structured verdict is in `{{VERDICT_FILE}}`; the full review, including
|
|
16
|
+
non-blocking notes, is in the task file's `## Code Review` section if a task file
|
|
17
|
+
is present.
|
|
18
|
+
|
|
19
|
+
## Deterministic gate
|
|
20
|
+
|
|
21
|
+
{{GATE_STATUS}}
|
|
22
|
+
|
|
23
|
+
If the gate is failing, that is your first priority — the review cannot clear
|
|
24
|
+
while it is red.
|
|
25
|
+
|
|
26
|
+
## How to respond
|
|
27
|
+
|
|
28
|
+
Address every blocking finding. For each one, either fix it or — if you believe
|
|
29
|
+
the reviewer is wrong — leave the code as it is and record a short rebuttal under a
|
|
30
|
+
`#### Response — Round {{ROUND}}` heading (in the task file's `## Code Review`
|
|
31
|
+
section if a task file is present, or in your final summary), naming the finding and
|
|
32
|
+
your reasoning. A disagreement recorded in writing is a legitimate outcome;
|
|
33
|
+
silently ignoring a finding is not.
|
|
34
|
+
|
|
35
|
+
Do not:
|
|
36
|
+
|
|
37
|
+
- Delete, skip, or weaken a test to make a finding or a gate go away. If a test
|
|
38
|
+
is genuinely wrong, fix the test and say so in the rebuttal.
|
|
39
|
+
- Fix anything the reviewer did not raise. Unrelated changes make the next
|
|
40
|
+
review round harder and can introduce new findings.
|
|
41
|
+
|
|
42
|
+
Scope and token discipline from the implementation phase still apply: work from
|
|
43
|
+
the files the findings name, keep command output short, and summarize before editing.
|
|
44
|
+
|
|
45
|
+
## Verification
|
|
46
|
+
|
|
47
|
+
Run the targeted tests for what you changed, then the gate commands:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
{{GATE_COMMANDS}}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Judge them by process exit code on unfiltered output.
|
|
54
|
+
|
|
55
|
+
At the end of the phase, commit the fixes and their tests in a conventional
|
|
56
|
+
commit whose message names the review findings addressed. Keep the worktree
|
|
57
|
+
clean for the next phase. If there is nothing to commit, leave the worktree clean.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Do a documentation-as-built pass with the committed work in the current
|
|
2
|
+
branch `{{BRANCH}}`, in the worktree at `{{REPO}}`. The work implements
|
|
3
|
+
`{{TASK_NAME}}` and has passed code review.
|
|
4
|
+
|
|
5
|
+
This is a docs/agent-guidance reconciliation pass only. Do not make code changes
|
|
6
|
+
unless they are strictly necessary to correct documentation generation or broken
|
|
7
|
+
references.
|
|
8
|
+
|
|
9
|
+
Audit the final as-built state and update durable documentation only where
|
|
10
|
+
needed:
|
|
11
|
+
|
|
12
|
+
Keep AGENTS.md light. It should orient coding agents and point them to the right
|
|
13
|
+
project documentation; it should not become the full documentation body.
|
|
14
|
+
Put substantive documentation for each major functionality area in docs/, split
|
|
15
|
+
by topic when that keeps files focused.
|
|
16
|
+
Ensure AGENTS.md references the relevant docs/ files so future agents know where
|
|
17
|
+
to find the information they need without loading everything.
|
|
18
|
+
Do not touch CLAUDE.md. It should already reference AGENTS.md and should remain
|
|
19
|
+
unchanged.
|
|
20
|
+
If docs are already accurate and appropriately structured, make no changes.
|
|
21
|
+
|
|
22
|
+
After the pass, run the smallest meaningful verification checks for
|
|
23
|
+
documentation changes, such as checking links/paths by inspection and
|
|
24
|
+
`git diff AGENTS.md` or `git diff docs` when applicable.
|
|
25
|
+
|
|
26
|
+
At the end of the phase, commit documentation changes in a `docs:` conventional
|
|
27
|
+
commit. Keep the worktree clean for the next phase. If the documentation is
|
|
28
|
+
already accurate, make no changes and leave the worktree clean.
|
|
29
|
+
|
|
30
|
+
If you find a bug while reading, note it in your final summary (and under `## Changelog` in the task file if present)
|
|
31
|
+
rather than fixing it; a code change at this point would go out unreviewed.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
The code-producing phases have already committed their work in `{{REPO}}`, on
|
|
2
|
+
branch `{{BRANCH}}`. Verify the worktree is clean and do not create any code
|
|
3
|
+
commits in this phase.
|
|
4
|
+
|
|
5
|
+
- Inspect the full worktree and recent branch history before pushing.
|
|
6
|
+
- Do _NOT_ include notes about co-author / author.
|
|
7
|
+
- Report the existing code commit hashes and messages, validation performed,
|
|
8
|
+
and whether the worktree is clean.
|
|
9
|
+
- Push to `{{REMOTE}}` and create a PR to `{{BASE_BRANCH}}` on the same repo. PR
|
|
10
|
+
body should be < 250 words.
|
|
11
|
+
|
|
12
|
+
The PR body should cover what changed and why, a summary of the task, the
|
|
13
|
+
review outcome (how many rounds, plus any recorded disagreements from the task file's
|
|
14
|
+
`## Code Review` section if present), and anything deliberately left out of scope.
|
|
15
|
+
|
|
16
|
+
## The task file
|
|
17
|
+
|
|
18
|
+
If a task file is present (`{{TASK_FILE}}`), update it without committing it:
|
|
19
|
+
|
|
20
|
+
- Set the frontmatter `status` to `UNDER REVIEW`.
|
|
21
|
+
- Append a `## Changelog` entry listing the code commits (short SHA + subject)
|
|
22
|
+
and the PR URL once you have it.
|
|
23
|
+
- Use only `TODO`, `IN PROGRESS`, `UNDER REVIEW`, or `DONE` as statuses.
|
|
24
|
+
|
|
25
|
+
A separate job or workflow commits task file changes if needed. Do not commit the
|
|
26
|
+
task file or make any other commits in its repository.
|
|
27
|
+
|
|
28
|
+
## Boundaries
|
|
29
|
+
|
|
30
|
+
- If the worktree is **not** clean — `git status --porcelain` reports anything —
|
|
31
|
+
do **not** edit files, tests, or configuration to make it clean, and do not
|
|
32
|
+
create commits. A dirty tree at this phase is a pipeline error: stop
|
|
33
|
+
immediately and report the offending paths. Reconciling it is out of scope
|
|
34
|
+
here, and the earlier phase that left the work uncommitted must be resumed
|
|
35
|
+
instead.
|
|
36
|
+
- **Do not merge the pull request**, and do not enable auto-merge. A human
|
|
37
|
+
decides; an open PR is the correct end state for this run.
|
|
38
|
+
- Never force-push, and never rewrite commits that already exist on
|
|
39
|
+
`{{REMOTE}}`.
|
|
40
|
+
- If the push is rejected because the branch moved, stop and report it rather
|
|
41
|
+
than forcing anything.
|
|
42
|
+
|
|
43
|
+
The separate task-file workflow and cron process own updates to that repository;
|
|
44
|
+
keep code and task-file commits separate.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{{TASK_CONTEXT}} The worktree at
|
|
2
|
+
`{{REPO}}` is already checked out to a new branch `{{BRANCH}}` off
|
|
3
|
+
`{{BASE_BRANCH}}` — work there, and do not create or switch branches.
|
|
4
|
+
|
|
5
|
+
Skip any steps that require manual human intervention. Implement the rest from
|
|
6
|
+
start to finish.
|
|
7
|
+
|
|
8
|
+
If a task file is present (`{{TASK_FILE}}`), update its frontmatter status to
|
|
9
|
+
`IN PROGRESS` before doing anything else in this first turn. The only allowed
|
|
10
|
+
statuses are `TODO`, `IN PROGRESS`, `UNDER REVIEW`, and `DONE`.
|
|
11
|
+
|
|
12
|
+
This run is unattended, so you cannot ask clarifying questions. Where you would
|
|
13
|
+
have asked, choose the reading most consistent with the task and the
|
|
14
|
+
surrounding code, and record the question and the assumption you made under
|
|
15
|
+
`## Changelog` in the task file (if present). If a step genuinely cannot proceed
|
|
16
|
+
without a human, implement everything else and record what you skipped and why.
|
|
17
|
+
|
|
18
|
+
Scope:
|
|
19
|
+
|
|
20
|
+
- Start with the files referenced in the task.
|
|
21
|
+
- Do _not_ scan or explore the whole repo.
|
|
22
|
+
- Only read additional files if they are imported or referenced in the task.
|
|
23
|
+
|
|
24
|
+
Token discipline:
|
|
25
|
+
|
|
26
|
+
- Keep command output short.
|
|
27
|
+
- Summarize findings before editing.
|
|
28
|
+
|
|
29
|
+
Verification:
|
|
30
|
+
|
|
31
|
+
- Add or update targeted tests.
|
|
32
|
+
- Run only the relevant test file first.
|
|
33
|
+
- Run broader tests after the targeted test passes.
|
|
34
|
+
- These commands gate the work and will be run against your changes, so run
|
|
35
|
+
them yourself before finishing:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
{{GATE_COMMANDS}}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- Judge them by process exit code on unfiltered output. A wrapper that
|
|
42
|
+
summarizes output can report a failure the tool never produced, and a cached
|
|
43
|
+
build can report success without compiling anything.
|
|
44
|
+
- At the end of the phase, commit the implementation and its targeted tests in
|
|
45
|
+
a conventional commit. Keep the worktree clean for the next phase.
|
|
46
|
+
- If a task file is present (`{{TASK_FILE}}`), keep it current by adding updates
|
|
47
|
+
to the `## Changelog` and updating status in the frontmatter when applicable.
|
|
48
|
+
Use only `TODO`, `IN PROGRESS`, `UNDER REVIEW`, or `DONE` as statuses.
|
|
49
|
+
- End your turn with a summary and next steps if applicable. The loop runs the
|
|
50
|
+
code review next, so you do not need to ask for one.
|