auto-mode 0.1.0 → 0.3.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/README.md CHANGED
@@ -1,12 +1,29 @@
1
- # auto-mode
1
+ <div align="center">
2
+ <h1>auto-mode</h1>
2
3
 
3
- A permission classifier that runs as a hook. It reads the agent's next action and
4
- answers allow, deny, or nothing at all — so you can leave an agent unattended
5
- without approving every step.
4
+ <p>
5
+ <a href="https://www.npmjs.com/package/auto-mode"><img src="https://img.shields.io/npm/v/auto-mode" alt="npm version"></a>
6
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
7
+ </p>
6
8
 
7
- Built for coding agents that are **not** Claude, in harnesses that are not Claude
8
- Code. Claude Code has its own auto mode; this gives the same shape to everything
9
- else.
9
+ <p>
10
+ <a href="./docs/README.md">Documentation</a> •
11
+ <a href="./docs/guides/configuration.md">Configuration</a> •
12
+ <a href="./policy/rules.md">The rules</a> •
13
+ <a href="./docs/architecture/overview.md">Architecture</a>
14
+ </p>
15
+ </div>
16
+
17
+ **auto-mode** is a permission classifier that runs as a hook. It decides whether a coding agent's
18
+ next action should run.
19
+
20
+ Claude Code's built-in auto mode judges actions only for Claude. Point Claude Code at another model
21
+ through an Anthropic-compatible gateway — GLM, Kimi, Muse Spark — and that judging stops. Every
22
+ shell command, file write, and push needs your approval again.
23
+
24
+ auto-mode replaces it. The harness calls it before a tool runs, hands it the pending call, and reads
25
+ back allow, deny, or nothing. It works in Claude Code, Codex, and Muse Code, and behaves the same
26
+ whichever model drives them.
10
27
 
11
28
  ## Install
12
29
 
@@ -15,130 +32,101 @@ npm i -g auto-mode
15
32
  auto-mode init claude # or codex, or muse
16
33
  ```
17
34
 
18
- `init` prints the hook entry and the path to paste it into. It does not write
19
- that file. Your settings are yours, and a tool that installs its own restraints
20
- can remove them.
21
-
22
- ## The two tiers
23
-
24
- 1. **Local rules.** Deterministic matching, no network call, well under a
25
- millisecond. It answers **allow** or **escalate** and never denies — a wrong
26
- local allow costs one unwatched action, a wrong local deny stops work you
27
- asked for.
28
- 2. **The model.** Everything the first tier declines goes to a small reasoning
29
- model with the policy as its system prompt. Measured at 13-24 seconds on a
30
- hard case, which is why tier one has to catch the ordinary ones.
31
-
32
- ## The policy
33
-
34
- Two files, and everything in them is what the model reads. Nothing there is
35
- addressed to you.
35
+ `init` prints the hook entry, the file to paste it into, and the extra step that harness needs. It
36
+ does not write the file itself.
36
37
 
37
- | File | What it holds | Change it to |
38
- |---|---|---|
39
- | `policy/rules.md` | 22 rules, 7 exceptions | Change what is blocked |
40
- | `policy/classifier.md` | Threat model, consent bar, evaluation rules, output contract | Change how judgement works |
38
+ The judging model needs a key. The default model is Muse Spark:
41
39
 
42
- `classifier.md` carries a `<rules>` marker on its own line. At run time auto-mode
43
- replaces it with the whole of `policy/rules.md` and the two become one prompt.
44
- `auto-mode print-prompt` writes exactly what the model receives.
40
+ ```sh
41
+ mkdir -p ~/.config/auto-mode
42
+ cat > ~/.config/auto-mode/config.json <<'JSON'
43
+ { "preset": "spark", "provider": { "apiKeyEnv": "META_API_KEY" } }
44
+ JSON
45
+ ```
45
46
 
46
- **Read `policy/rules.md` before you turn this on.** If you disagree with a rule,
47
- change the rule.
47
+ Presets for `claude` and `glm` ship too. See [Configuration](./docs/guides/configuration.md).
48
48
 
49
- ## Configuration
49
+ ## How it decides
50
50
 
51
- `~/.config/auto-mode/config.json`. Everything has a default; the file is
52
- optional.
51
+ Two tiers.
53
52
 
54
- ```json
55
- {
56
- "preset": "spark",
57
- "provider": { "apiKeyCommand": "my-key-helper" },
58
- "onFailure": "defer"
59
- }
60
- ```
53
+ 1. **Local rules.** Deterministic matching, no network call, under a millisecond. Answers allow or
54
+ escalate, never deny. Reads, listings, `git status`, and deleting build output are settled here
55
+ and never reach the model.
56
+ 2. **The model.** Everything else goes to a small reasoning model with the policy as its system
57
+ prompt. A hard case takes 13 to 24 seconds.
61
58
 
62
- Three presets: `spark` (the default), `claude`, `glm`. Each names a base URL, a
63
- model, a key source, and the three settings that move together — whether the
64
- model reasons, its token budget, and its timeout.
59
+ Tier one never denies because the two errors cost differently. A wrong allow costs one unwatched
60
+ action. A wrong deny stops work you asked for, and the rules that deny are prose that needs a
61
+ reader.
65
62
 
66
- | Key | Default | Meaning |
67
- |---|---|---|
68
- | `preset` | `spark` | Which provider to start from |
69
- | `provider.*` | from the preset | Override any single field |
70
- | `classifierPath`, `rulesPath` | the shipped files | Use your own policy |
71
- | `transcriptEntries` | `40` | How much history the model sees |
72
- | `onFailure` | `defer` | `defer` writes nothing; `deny` fails closed |
63
+ ## The policy
73
64
 
74
- **Muse Spark is the default** because it reasons, it was correct on every case
75
- measured, and a contributor-tier call costs roughly a fortieth of the
76
- alternatives. Its token budget is a floor, not a preference: below it, Spark
77
- returns nothing at all.
65
+ Two files. Both are sent to the model verbatim, and neither addresses you.
78
66
 
79
- The key comes from `provider.apiKeyEnv` first, then from `provider.apiKeyCommand`
80
- if that is unset. Muse runs hooks with a scrubbed environment, so under Muse the
81
- command is the only one that works.
67
+ | File | Holds | Edit it to |
68
+ | ------------------------------------------------ | ------------------------------------------------------------ | -------------------------- |
69
+ | [`policy/rules.md`](./policy/rules.md) | 22 rules, 7 exceptions | Change what is blocked |
70
+ | [`policy/classifier.md`](./policy/classifier.md) | Threat model, consent bar, evaluation rules, output contract | Change how judgement works |
82
71
 
83
- ## Writing nothing is an answer
72
+ `classifier.md` carries a `<rules>` marker on its own line. At run time auto-mode replaces it with
73
+ the whole of `rules.md`. `auto-mode print-prompt` writes the result, which is what the model reads.
84
74
 
85
- It means auto-mode has no opinion, and the harness then does what it would have
86
- done alone. That is the output for an unknown harness, an event that is not a
87
- tool gate, malformed input, a missing key, and a model that times out. So this
88
- can only turn an ask into an allow or a deny — it never removes a gate that was
89
- already there.
75
+ Rules come in two tiers. A **hard block** takes no consent, because it creates a risk you cannot see
76
+ from inside the session. A **soft block** clears when you named the action and the detail that makes
77
+ it dangerous — "force push this branch", not "tidy up the repo". Seven exceptions cover work that
78
+ resembles a blocked action and is not: deleting `node_modules`, running a formatter, dropping a
79
+ local test database.
90
80
 
91
- Set `onFailure` to `deny` if you would rather fail closed.
81
+ Read [`policy/rules.md`](./policy/rules.md) before turning this on. To change a rule, edit it;
82
+ `rulesPath` points at your own file and replaces the shipped one whole.
92
83
 
93
84
  ## Harnesses
94
85
 
95
- Claude Code, Codex, and Muse Code. The verdict contract is the same for all
96
- three, and all three were verified end to end: the hook denied a real tool call
97
- and each harness stopped it.
98
-
99
- They differ in how the hook is registered, and each difference makes the hook
100
- silently not run if you get it wrong. `auto-mode init` prints these.
86
+ All three were verified end to end: the hook denied a real tool call and the harness stopped it.
101
87
 
102
- | Harness | Match every tool | Also needed |
103
- |---|---|---|
104
- | Claude | `"matcher": ".*"` | — |
105
- | Codex | omit `matcher` | `hooks = true`, and trust the hook once |
106
- | Muse | `"matcher": ""` | no `timeout_ms` key |
88
+ | Harness | Match every tool | Also needed |
89
+ | ----------- | ----------------- | --------------------------------------- |
90
+ | Claude Code | `"matcher": ".*"` | — |
91
+ | Codex | omit `matcher` | `hooks = true`, and trust the hook once |
92
+ | Muse Code | `"matcher": ""` | no `timeout_ms` key |
107
93
 
108
- Three traps worth naming:
94
+ Each difference stops the hook running if you get it wrong, and none of them reports an error.
95
+ `init` prints the right one. Details in [Harnesses](./docs/guides/harnesses.md).
109
96
 
110
- - Claude matches tool names against a **regular expression**. `"*"` is not valid
111
- regex and `""` matches only a tool named empty; both leave the hook installed
112
- and never firing. Muse reads `""` as every tool, so the same value means
113
- opposite things in the two harnesses.
114
- - Codex will not run an **untrusted** hook. It is skipped silently until you
115
- trust it once; the answer is recorded under `[hooks.state]` in `config.toml`.
116
- - Muse **rejects a handler carrying `timeout_ms`**, reporting an unknown field
117
- and skipping the whole handler.
118
-
119
- Detection order matters too. Muse is identified by `model_provider`, which the
120
- others do not send. Claude sends `prompt_id`. Codex sends `turn_id` — and so
121
- does Muse, so Muse has to be tested first.
97
+ ## Writing nothing is an answer
122
98
 
123
- ## What this cannot do
99
+ It means auto-mode has no opinion, and the harness does what it would have done alone. That is the
100
+ output for an unknown harness, an event that is not a tool gate, malformed input, a missing key, and
101
+ a model that times out.
124
102
 
125
- - **A hook that cannot start fails open.** If the command is missing or crashes,
126
- the harness logs it and carries on. `onFailure: "deny"` cannot help, because
127
- the process never runs.
128
- - **It can only narrow what the harness already allows.** A tool your own
129
- permission settings deny is refused before the hook sees it.
130
- - **The agent's own judgement comes first.** A model that refuses to issue a
131
- command means the hook is never consulted for it.
103
+ auto-mode can therefore only narrow what your harness already allows. It never removes a gate that
104
+ was there. Set `onFailure` to `deny` to fail closed instead.
132
105
 
133
106
  ## Commands
134
107
 
135
- | Command | What it does |
136
- |---|---|
137
- | `auto-mode run` | Read a payload on stdin, write a verdict on stdout |
138
- | `auto-mode run --explain` | Also write the reasoning to stderr |
139
- | `auto-mode run --local-only` | Skip the model tier |
140
- | `auto-mode print-prompt` | Print the assembled system prompt |
141
- | `auto-mode init <harness>` | Print the hook entry to add |
108
+ | Command | What it does |
109
+ | ---------------------------- | -------------------------------------------------- |
110
+ | `auto-mode run` | Read a payload on stdin, write a verdict on stdout |
111
+ | `auto-mode run --explain` | Also write the reasoning to stderr |
112
+ | `auto-mode run --local-only` | Skip the model tier |
113
+ | `auto-mode print-prompt` | Print the assembled system prompt |
114
+ | `auto-mode init <harness>` | Print the hook entry to add |
115
+
116
+ `init` takes `--event permission-request` to register on the event Claude Code sends when it is
117
+ about to ask you, rather than on every tool call. The
118
+ [harness guide](./docs/guides/harnesses.md#which-event) covers the choice.
119
+
120
+ ## Documentation
121
+
122
+ - [Overview](./docs/architecture/overview.md) — the two tiers, harness detection, the verdict
123
+ contract, prompt caching, and the failure modes.
124
+ - [Configuration](./docs/guides/configuration.md) — every field, every preset, and how the key is
125
+ found.
126
+ - [Harnesses](./docs/guides/harnesses.md) — installing into Claude Code, Codex, and Muse Code, and
127
+ what each does differently.
128
+ - [Writing a policy](./docs/guides/policy.md) — the rule tiers, the consent bar, and how to change
129
+ or replace the shipped rules.
142
130
 
143
131
  ## Licence
144
132