@czottmann/pi-automode 0.1.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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2026 Carlo Zottmann
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,211 @@
1
+ # pi-automode
2
+
3
+ Claude Code-style auto mode for Pi.
4
+
5
+ This is a guardrail extension. It intercepts agent tool calls before execution and blocks actions that match permission deny rules, deterministic hard-deny checks, or the auto-mode classifier's block decision.
6
+
7
+ It is not a sandbox. Extensions run in the Pi process, and a determined malicious extension can do anything your user account can do. It also does not guard user `!` / `!!` shell commands; by design, it guards agent tool calls only. Use this to reduce unsafe autonomous tool use, not as an OS security boundary.
8
+
9
+ ## Install
10
+
11
+ From npm:
12
+
13
+ ```bash
14
+ pi install npm:@czottmann/pi-automode
15
+ ```
16
+
17
+ From a local checkout:
18
+
19
+ ```bash
20
+ pi install .
21
+ ```
22
+
23
+ For one run from a local checkout:
24
+
25
+ ```bash
26
+ pi -e ./extensions/auto-mode.ts
27
+ ```
28
+
29
+ ## Commands
30
+
31
+ ```text
32
+ /automode status # current state, rules, and classifier
33
+ /automode on # re-enable for this session
34
+ /automode off # disable for this session
35
+ /automode reload # reload config from disk
36
+ /automode reset # reset denial counters only
37
+ /automode defaults # print the built-in rule lists
38
+ /automode config # current effective config + diagnostics
39
+ /automode denials # denial history for this session
40
+ /automode model # open classifier model selector
41
+ /automode model provider/model-id # set classifier directly
42
+ ```
43
+
44
+ `/auto-mode` is an alias.
45
+
46
+ ## Configuration
47
+
48
+ The extension follows Claude Code's documented config model where Pi can support it.
49
+
50
+ It reads `autoMode` from Pi-owned config only:
51
+
52
+ - `~/.pi/automode.json`
53
+ - `.pi/automode.local.json`
54
+ - `PI_AUTOMODE_SETTINGS_JSON`
55
+
56
+ It deliberately does not read `autoMode` from shared project `.pi/automode.json`, because a checked-in repo should not be able to weaken auto-mode rules. Shared project config may still contribute `permissions.deny` and `permissions.ask`.
57
+
58
+ Example:
59
+
60
+ ```json
61
+ {
62
+ "autoMode": {
63
+ "environment": [
64
+ "$defaults",
65
+ "Source control: github.example.com/acme-corp and all repos under it",
66
+ "Trusted internal domains: *.corp.example.com"
67
+ ],
68
+ "allow": ["$defaults"],
69
+ "soft_deny": ["$defaults"],
70
+ "hard_deny": [
71
+ "$defaults",
72
+ "Never send repository contents to third-party code-review APIs"
73
+ ]
74
+ },
75
+ "permissions": {
76
+ "deny": ["bash(rm -rf *)"],
77
+ "ask": ["bash(git push *)"]
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### `$defaults`
83
+
84
+ `$defaults` expands to this plugin's built-in entries for the section where it appears. It is section-local: `$defaults` in `allow` means the built-in allow rules, not the built-in hard-deny rules.
85
+
86
+ #### `environment`
87
+
88
+ `$defaults` expands to:
89
+
90
+ - trusted repo: the repository Pi started in and its configured git remotes
91
+ - source control: the trusted repo and its configured remotes only
92
+ - trusted internal domains: none configured
93
+ - trusted cloud buckets: none configured
94
+ - key internal services: none configured
95
+
96
+ #### `allow`
97
+
98
+ `$defaults` expands to allow exceptions for:
99
+
100
+ - read-only operations: inspecting files, listing directories, searching, GET requests, and state queries that do not expose secrets
101
+ - local development inside the working tree: creating, editing, building, testing, linting, formatting, and deleting files created during the current task
102
+ - installing dependencies already declared in package manifests or lockfiles
103
+ - using standard credentials only with their intended configured providers
104
+ - pushing to the current non-default working branch or a new branch created for the task
105
+ - bootstrapping language/toolchain installers from official sources
106
+
107
+ These are exceptions to `soft_deny`, not to `hard_deny`.
108
+
109
+ #### `soft_deny`
110
+
111
+ `$defaults` expands to soft blocks for:
112
+
113
+ - force push, remote branch deletion, remote history rewrite, or direct push to `main`, `master`, or the default branch
114
+ - downloading and executing external code, including `curl | bash` and `wget | sh`
115
+ - production deploys, production database migrations, or production infrastructure changes
116
+ - deleting, truncating, or overwriting pre-existing local files unless the user named the specific target
117
+ - mass modification/deletion in cloud storage, ticketing systems, collaboration tools, or external APIs
118
+ - writing through remote shells such as `ssh`, `kubectl exec`, or `docker exec` on shared or production hosts
119
+ - changing live/shared infrastructure without a preview, plan, dry-run, or review when one normally exists
120
+ - killing other users' processes, cancelling shared jobs, or disrupting shared infrastructure
121
+ - exposing local files, sockets, credentials, or internal services through a network service
122
+ - outbound messages, purchases, bookings, subscriptions, or other real-world transactions
123
+
124
+ Soft blocks can be overridden by a matching `allow` exception or by direct, specific user intent.
125
+
126
+ #### `hard_deny`
127
+
128
+ `$defaults` expands to unconditional blocks for:
129
+
130
+ - weakening TLS, certificate validation, authentication, authorization, audit logging, or other security controls
131
+ - adding persistence such as SSH keys, shell profile edits, cron jobs, launch agents, login items, or background agents
132
+ - granting admin, owner, IAM, RBAC, repository, or production access
133
+ - exfiltrating repository contents, secrets, credentials, private keys, tokens, or internal data to untrusted places
134
+ - scanning for credentials, tokens, private keys, or secrets beyond what the task requires
135
+ - tampering with logs, audit trails, security monitoring, permission rules, auto-mode config, or safety-control files
136
+ - creating services, endpoints, workflows, or autonomous agents that execute arbitrary code without meaningful approval
137
+ - posting or updating public/external content that is fabricated, misleading, impersonating a user, or claiming approval/action that did not happen
138
+
139
+ Hard-deny rules cannot be overridden by `allow` or by user intent.
140
+
141
+ #### Replacement behavior
142
+
143
+ Use `$defaults` when you want to keep the built-ins and add your own entries:
144
+
145
+ ```json
146
+ {
147
+ "autoMode": {
148
+ "allow": [
149
+ "$defaults",
150
+ "Running the staging deploy script is allowed."
151
+ ]
152
+ }
153
+ }
154
+ ```
155
+
156
+ That means: use all built-in `allow` entries, plus the staging rule.
157
+
158
+ If you omit `$defaults`, you replace the built-ins for that section:
159
+
160
+ ```json
161
+ {
162
+ "autoMode": {
163
+ "allow": [
164
+ "Running the staging deploy script is allowed."
165
+ ]
166
+ }
167
+ }
168
+ ```
169
+
170
+ That means: use only that one `allow` entry. The built-in `allow` entries are not used. Replacing `allow` does not replace `soft_deny`, `hard_deny`, or `environment`.
171
+
172
+ `$defaults` is not used in `permissions.deny` or `permissions.ask`. Those lists contain only explicit Pi tool patterns.
173
+
174
+ ### Permission patterns
175
+
176
+ Permission patterns use Pi tool names, for example `bash(...)`, `write(...)`, `edit(...)`, `read(...)`. The parser accepts capitalized names like `Bash(...)` for convenience, but the documented form is lowercase because Pi tool names are lowercase.
177
+
178
+ ## What is enforced before the classifier
179
+
180
+ The extension blocks these before any allow or classifier decision:
181
+
182
+ - `permissions.deny` matches
183
+ - declined `permissions.ask` matches
184
+ - shell profile writes
185
+ - SSH `authorized_keys` writes
186
+ - cron, launch agent, and system service persistence
187
+ - TLS/certificate/auth weakening patterns
188
+ - root, home, and system-path destructive deletes
189
+ - edits to `.pi/automode*`, `.pi` auto-mode files, and this extension's safety-control files
190
+
191
+ Read-only Pi tools (`read`, `grep`, `find`, `ls`) are allowed after those checks.
192
+
193
+ Everything else goes to the classifier. If the classifier is missing, fails, or returns invalid JSON, the action is blocked.
194
+
195
+ ## Examples
196
+
197
+ - `examples/automode.local.json`: copy to `.pi/automode.local.json` in a project and edit the domains, buckets, and source-control org.
198
+
199
+ ## Development
200
+
201
+ ```bash
202
+ npm run check
203
+ npm test
204
+ npm pack --dry-run
205
+ ```
206
+
207
+ The tests cover the risky parts: scoped permission matching, config-source precedence, `$defaults` behavior, config diagnostics, deterministic hard-deny checks, shell parsing for risky bash fragments, classifier JSON parsing, hook-level blocking/allowing, and classifier mocking.
208
+
209
+ ## Known limits
210
+
211
+ Claude Code's real classifier and exact built-in rules are private. This package implements the documented precedence and configuration behavior, with a local classifier prompt and deterministic hard-deny checks.
@@ -0,0 +1,32 @@
1
+ {
2
+ "autoMode": {
3
+ "environment": [
4
+ "$defaults",
5
+ "Source control: github.example.com/acme-corp and all repos under it",
6
+ "Trusted internal domains: *.corp.example.com, api.internal.example.com",
7
+ "Trusted cloud buckets: s3://acme-build-artifacts, gs://acme-dev-scratch"
8
+ ],
9
+ "allow": [
10
+ "$defaults",
11
+ "Deploying to the staging namespace is allowed when the command names staging explicitly."
12
+ ],
13
+ "soft_deny": [
14
+ "$defaults",
15
+ "Never run database migrations except through the project's migrations CLI."
16
+ ],
17
+ "hard_deny": [
18
+ "$defaults",
19
+ "Never send repository contents to third-party code-review APIs."
20
+ ]
21
+ },
22
+ "permissions": {
23
+ "ask": [
24
+ "bash(git push *)"
25
+ ],
26
+ "deny": [
27
+ "bash(git push --force*)",
28
+ "edit(.env*)",
29
+ "write(.env*)"
30
+ ]
31
+ }
32
+ }