@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.34 → 0.1.37
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/bin/adl +2 -2
- package/bin/reconcile +4 -3
- package/package.json +1 -1
- package/packages/agent-hooks/README.md +14 -0
- package/packages/agent-hooks/assets/opencode-plugin.template.ts +140 -104
- package/packages/agent-hooks/deploy-profile.json +1 -1
- package/packages/agent-hooks/src/deploy/opencode-template.ts +5 -18
- package/packages/agent-hooks/src/deploy/render.ts +12 -3
- package/packages/agent-hooks/src/pre-tool-use/handler.ts +2 -2
- package/packages/agent-hooks/src/rules/impl/adl-build-run-role.ts +116 -0
- package/packages/agent-hooks/src/rules/impl/adl-git-user-override-block.ts +159 -0
- package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +12 -6
- package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +9 -9
- package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +6 -5
- package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +15 -14
- package/packages/agent-hooks/src/rules/impl/git-core.ts +4 -8
- package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +1 -1
- package/packages/agent-hooks/src/rules/impl/tool-native-search.ts +8 -7
- package/packages/agent-hooks/src/rules/registry.ts +11 -2
- package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +9 -5
- package/packages/agent-settings/README.md +10 -4
- package/packages/agent-settings/assets/TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md +40 -0
- package/packages/agent-settings/src/global-agents.ts +43 -8
- package/packages/agent-skills/assets/adl-mechanics/SKILL.md +38 -0
- package/packages/agent-skills/assets/agent-search-tool-audit/scripts/audit.sh +1 -1
- package/packages/agent-skills/assets/code-review/SKILL.md +84 -66
- package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +23 -2
- package/packages/agent-skills/assets/diagnosing-bugs/references/FEEDBACK-LOOP-TACTICS.md +1 -1
- package/packages/agent-skills/assets/explore-codebase/SKILL.md +3 -2
- package/packages/agent-skills/assets/finalize-feature/SKILL.md +63 -0
- package/packages/agent-skills/assets/fix-ci/SKILL.md +58 -0
- package/packages/agent-skills/assets/handoff/SKILL.md +1 -1
- package/packages/agent-skills/assets/implement-feature/SKILL.md +153 -0
- package/packages/agent-skills/assets/implement-feature/references/briefs.md +94 -0
- package/packages/agent-skills/assets/implement-item/SKILL.md +71 -0
- package/packages/agent-skills/assets/mechanics/SKILL.md +38 -0
- package/packages/agent-skills/assets/plan-feature/SKILL.md +141 -0
- package/packages/agent-skills/assets/prepare-promotion/SKILL.md +91 -0
- package/packages/agent-skills/assets/ralplan/SKILL.md +149 -0
- package/packages/agent-skills/assets/refactor-safely/SKILL.md +4 -3
- package/packages/agent-skills/assets/report-bug/SKILL.md +72 -0
- package/packages/agent-skills/assets/review-change/SKILL.md +82 -0
- package/packages/agent-skills/assets/review-plan/SKILL.md +124 -0
- package/packages/agent-skills/assets/to-feature/SKILL.md +1 -1
- package/packages/agent-skills/assets/to-workitems/SKILL.md +1 -1
- package/packages/agent-skills/assets/to-workitems/references/AZURE-DEVOPS-HIERARCHY.md +3 -0
- package/packages/agent-skills/assets/triage-workitems/SKILL.md +99 -0
- package/packages/agent-skills/assets/ultragoal/SKILL.md +77 -0
- package/packages/agent-skills/assets/validate-design/SKILL.md +70 -0
- package/packages/agent-skills/assets/verify-item/SKILL.md +71 -0
- package/packages/agent-skills/assets/workitems-process/SKILL.md +147 -0
- package/packages/agent-skills/assets/workitems-process/references/ado-and-git.md +194 -0
- package/packages/agent-skills/assets/workitems-process/references/evidence.md +74 -0
- package/packages/agent-skills/assets/workitems-process/references/workitem-states.md +92 -0
- package/packages/agent-skills/assets/write-feature/SKILL.md +95 -0
- package/packages/agent-skills/dist/deploy.d.ts +7 -0
- package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
- package/packages/agent-skills/dist/deploy.js +52 -5
- package/packages/agent-skills/dist/deploy.js.map +1 -1
- package/packages/agent-skills/src/deploy.ts +48 -4
- package/packages/azdo/scripts/probe-ado-rules.ts +1 -1
- package/packages/azdo/src/activity-log.ts +118 -0
- package/packages/azdo/src/azdo-attachments.ts +108 -0
- package/packages/azdo/src/azdo-pl.ts +100 -3
- package/packages/azdo/src/azdo-pr.ts +194 -11
- package/packages/azdo/src/azdo-wit.ts +329 -18
- package/packages/azdo/src/cli.ts +42 -2
- package/packages/azdo/src/lib/agent-identity.ts +1 -1
- package/packages/azdo/src/lib/client.ts +7 -1
- package/packages/azdo/src/lib/validate-pr-metadata.ts +14 -5
- package/packages/azdo/src/mcp-server.ts +53 -5
- package/packages/azdo/src/tool-dispatch.ts +53 -4
- package/packages/azdo/src/workflow-ladder.csv +125 -107
- package/packages/azdo/src/workflow-rules.ts +254 -97
- package/packages/repo-controls/README.md +24 -11
- package/packages/repo-controls/assets/scaffold/docs/AGENTS.md +5 -5
- package/packages/repo-controls/assets/scaffold/plans/AGENTS.md +42 -13
- package/packages/repo-controls/assets/scaffold/root/AGENTS.md +60 -11
- package/packages/repo-controls/assets/scaffold/root/CONTRIBUTING.md +28 -0
- package/packages/repo-controls/assets/scaffold/root/INVARIANTS.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +0 -11
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +4 -6
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +15 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +1 -17
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +3 -22
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +39 -182
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/intent.md +17 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +90 -321
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +31 -5
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +282 -54
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/design.md +35 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/file-map-reference.md +19 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/intent.md +25 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +25 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/requirements.md +44 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/requirements.md +44 -0
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +646 -53
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +3 -3
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +1 -12
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +1 -1
- package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +1 -1
- package/packages/repo-controls/src/cli.ts +23 -5
- package/packages/repo-controls/src/constants.ts +2 -15
- package/packages/repo-controls/src/install.ts +15 -6
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/** `adl.git-user-override-block` — blanket deny (2026-10-12) of every `user.name` / `user.email` / `user.useConfigOnly` override on a git command: inline `-c user.*=…` / `--config-env user.*=…` (separated, bundled, or bare next-token), the `GIT_CONFIG_COUNT` / `GIT_CONFIG_KEY_<n>` / `GIT_CONFIG_VALUE_<n>` env-var equivalent, AND any `git config` invocation at all (read or write — the whole subcommand is closed; an agent that needs the current identity runs `git var GIT_AUTHOR_IDENT` or reads `.git/config` directly). The only allowed identity path is `ADL_AGENT_ID_AGENT=agent-tarun` on the command line so the front controller (`bin/git-ado`) stamps the right committer. Placed 3rd in `GIT_RULES`, right after the two `core.*` override rules, so a `user.*` ride-along on any subcommand reports as the user override, not the subcommand rule. The pre-commit hook (the `prepare-commit-msg` / `commit-msg` pair `bin/git-ado` calls) used to catch the *result* on `git commit`, but not on `git commit-tree` / `git fast-import` / etc. — this rule closes the gap at the command level, before git ever sees the override. */
|
|
2
|
+
|
|
3
|
+
import { isHelpOnlyInvocation } from './git-helpers.ts'
|
|
4
|
+
import type { Finding, MessageContext, RuleContext, RuleSpec } from '../spec.ts'
|
|
5
|
+
import { noParams } from '../spec.ts'
|
|
6
|
+
import { gitAgentTail } from './messages.ts'
|
|
7
|
+
import type { Invocation } from '../shell/invocation.ts'
|
|
8
|
+
import { tokenValue } from '../shell/token.ts'
|
|
9
|
+
|
|
10
|
+
/** `user.name`, `user.email`, `user.useConfigOnly` — case-insensitive. */
|
|
11
|
+
const USER_KEY = /^user\.(name|email|useconfigonly)\b/i
|
|
12
|
+
|
|
13
|
+
/** `GIT_CONFIG_COUNT=<n>` where `<n>` is a non-zero integer — captured so the env-var form's scope gate (the COUNT must be non-zero for git to read any of the KEY/VALUE pairs) is enforced, not assumed. */
|
|
14
|
+
const GIT_CONFIG_COUNT_RE = /\bGIT_CONFIG_COUNT\s*=\s*([1-9]\d*)\b/i
|
|
15
|
+
/** `GIT_CONFIG_KEY_<n>=<value>` — `<value>` is checked against `USER_KEY` separately. */
|
|
16
|
+
const GIT_CONFIG_KEY_RE = /\bGIT_CONFIG_KEY_\d+\s*=\s*([^\s'"`;&|<>(){}]+)/gi
|
|
17
|
+
|
|
18
|
+
function gitInvocation(inv: Invocation): Invocation & { kind: 'git' } | null {
|
|
19
|
+
return inv.kind === 'git' ? inv : null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** True when `tokens` (the post-`-c` value tokens) contains a `user.*` key; strips a single leading `-c` so the bundled `-cuser.name=Foo` form (whole-token consumed by `scanGitGlobals`) matches the same regex as the separated form. */
|
|
23
|
+
function tokensOverrideUser(tokens: readonly { readonly value: string }[]): boolean {
|
|
24
|
+
for (const token of tokens) {
|
|
25
|
+
const raw = tokenValue(token as Parameters<typeof tokenValue>[0])
|
|
26
|
+
// Bundled `-cuser.name=Foo`: drop the leading `-c` so the regex below matches.
|
|
27
|
+
const value = raw.startsWith('-c') && raw.length > 2 ? raw.slice(2) : raw
|
|
28
|
+
if (USER_KEY.test(value)) return true
|
|
29
|
+
}
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** True when `command` carries the `GIT_CONFIG_*` env-var form of a `user.*` override: a non-zero `GIT_CONFIG_COUNT=<n>` AND at least one `GIT_CONFIG_KEY_<n>=user.<…>` (both must be present; a lone KEY without a non-zero COUNT is a no-op and not a bypass). */
|
|
34
|
+
function envVarOverrideUser(command: string): boolean {
|
|
35
|
+
if (!GIT_CONFIG_COUNT_RE.test(command)) return false
|
|
36
|
+
// Reset the shared `g`-flag regex's lastIndex between calls (stateful).
|
|
37
|
+
GIT_CONFIG_KEY_RE.lastIndex = 0
|
|
38
|
+
for (;;) {
|
|
39
|
+
const match = GIT_CONFIG_KEY_RE.exec(command)
|
|
40
|
+
if (match === null) return false
|
|
41
|
+
if (USER_KEY.test(match[1] as string)) return true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const adlGitUserOverrideBlock: RuleSpec = {
|
|
46
|
+
id: 'adl.git-user-override-block',
|
|
47
|
+
category: 'git',
|
|
48
|
+
severity: 'deny',
|
|
49
|
+
enabledByDefault: true,
|
|
50
|
+
summary: 'Blanket deny (2026-10-12) of every `user.*` override on a git command: inline `-c` / `--config-env`, the `GIT_CONFIG_*` env-var equivalent, AND any `git config` invocation at all (read or write — the whole subcommand is closed; `git var GIT_AUTHOR_IDENT` is the only way an agent reads the current identity). The only allowed identity path is `ADL_AGENT_ID_AGENT=agent-tarun` on the command line.',
|
|
51
|
+
params: noParams,
|
|
52
|
+
match(inv, ctx: RuleContext<Record<string, never>>): Finding | null {
|
|
53
|
+
const git = gitInvocation(inv)
|
|
54
|
+
if (!git) return null
|
|
55
|
+
if (isHelpOnlyInvocation(git.rest)) return null
|
|
56
|
+
// Blanket inline-override surface: `-c user.*=…` / `--config-env user.*=…` (and the bare-token / bundled forms) land in `git.globals`.
|
|
57
|
+
if (tokensOverrideUser(git.globals)) {
|
|
58
|
+
return { ruleId: 'adl.git-user-override-block', severity: 'deny', detail: {} }
|
|
59
|
+
}
|
|
60
|
+
// Env-var form: `GIT_CONFIG_*` assignments are consumed by `walk()` before the `git` Invocation is built; scan the raw `ctx.command`.
|
|
61
|
+
if (ctx.command !== undefined && envVarOverrideUser(ctx.command)) {
|
|
62
|
+
return { ruleId: 'adl.git-user-override-block', severity: 'deny', detail: {} }
|
|
63
|
+
}
|
|
64
|
+
// Per the 2026-10-12 widening: `git config` is BANNED for agents — every invocation, read or write. An agent that needs to know the current `user.name` runs `git var GIT_AUTHOR_IDENT` or reads `.git/config` directly; `git config` of any kind is the surface that touches persisted config and is closed.
|
|
65
|
+
if (git.subcommand === 'config') {
|
|
66
|
+
return { ruleId: 'adl.git-user-override-block', severity: 'deny', detail: {} }
|
|
67
|
+
}
|
|
68
|
+
return null
|
|
69
|
+
},
|
|
70
|
+
message(_finding: Finding, ctx: MessageContext) {
|
|
71
|
+
return {
|
|
72
|
+
user:
|
|
73
|
+
'Blocked a user.name / user.email / user.useConfigOnly override on a git command. ' +
|
|
74
|
+
'Inline `-c user.*=…`, `--config-env user.*=`, `GIT_CONFIG_KEY_<n>=user.*` env-var overrides, AND any `git config` invocation are all banned in an agent session.',
|
|
75
|
+
agent:
|
|
76
|
+
'DENIED user-identity override on a git command. `git -c user.name=…` / `-c user.email=…` / ' +
|
|
77
|
+
'`--config-env user.*=…` (in every form — separated, bundled as `-cuser.*=…`, or bare ' +
|
|
78
|
+
'`-c user.* …`); the `GIT_CONFIG_COUNT=<n> GIT_CONFIG_KEY_<n>=user.* GIT_CONFIG_VALUE_<n>=…` ' +
|
|
79
|
+
'env-var form (per `git-config(1)`); AND `git config …` of any kind (read or write — the whole ' +
|
|
80
|
+
'subcommand is closed in an agent session) are blanket-denied in an agent session (2026-10-12). ' +
|
|
81
|
+
'The only allowed identity path is `ADL_AGENT_ID_AGENT=agent-tarun` on the command line: ' +
|
|
82
|
+
'`ADL_AGENT_ID_AGENT=agent-tarun git commit -m …` so the front controller (`bin/git-ado`) ' +
|
|
83
|
+
'stamps the right committer. To read the current identity, run `git var GIT_AUTHOR_IDENT` or ' +
|
|
84
|
+
'read `.git/config` directly — `git config` is NEVER the right answer in an agent session, ' +
|
|
85
|
+
`even as a one-shot. ${gitAgentTail(ctx.snippet)}`,
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
corpus: {
|
|
89
|
+
deny: [
|
|
90
|
+
// `-c user.*=` (separate token)
|
|
91
|
+
'git -c user.name=Foo commit -m x',
|
|
92
|
+
'git -c user.email=foo@bar commit -m x',
|
|
93
|
+
'git -c user.useConfigOnly=true commit -m x',
|
|
94
|
+
// `-c` bundled with `=` (no space) — the same form `scanGitGlobals` folds
|
|
95
|
+
'git -cuser.name=Foo commit -m x',
|
|
96
|
+
'git -cuser.email=foo@bar commit -m x',
|
|
97
|
+
// bare `-c` + separate-token value (next-token form)
|
|
98
|
+
'git -c user.name Foo commit -m x',
|
|
99
|
+
'git -c user.email foo@bar commit -m x',
|
|
100
|
+
// Case-insensitive
|
|
101
|
+
'git -c User.Name=Foo commit -m x',
|
|
102
|
+
'git -c USER.EMAIL=foo@bar commit -m x',
|
|
103
|
+
// `--config-env` (the env-var form, not just `-c`)
|
|
104
|
+
'git --config-env user.name=Foo commit -m x',
|
|
105
|
+
// `user.*` ride-along with a non-commit subcommand — still blocked (blanket)
|
|
106
|
+
'git -c user.name=Foo push',
|
|
107
|
+
'git -c user.name=Foo push origin main',
|
|
108
|
+
'git -c user.email=foo@bar fetch',
|
|
109
|
+
'git -c user.name=Foo log --oneline',
|
|
110
|
+
'git -c user.email=foo@bar status',
|
|
111
|
+
// The GIT_CONFIG_* env-var form — git's own alternative to `-c`; COUNT must be non-zero AND a KEY_<n>=user.* must be present for the bypass to take effect (the rule denies on that pair).
|
|
112
|
+
'GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=Foo git commit -m x',
|
|
113
|
+
'GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.email GIT_CONFIG_VALUE_0=foo@bar git commit -m x',
|
|
114
|
+
'GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.useConfigOnly GIT_CONFIG_VALUE_0=true git commit -m x',
|
|
115
|
+
// Same, riding along with a non-commit subcommand
|
|
116
|
+
'GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=Foo git push',
|
|
117
|
+
'GIT_CONFIG_COUNT=2 GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=Foo GIT_CONFIG_KEY_1=user.email GIT_CONFIG_VALUE_1=foo@bar git commit -m x',
|
|
118
|
+
// Persistent form: `git config user.* …` (including `--global` / `--local` / `--unset` / `--remove-section user`).
|
|
119
|
+
'git config user.name "agent-tarun"',
|
|
120
|
+
'git config --global user.name "agent-tarun"',
|
|
121
|
+
'git config --local user.email "agent-tarun@<org-domain>"',
|
|
122
|
+
'git config user.useConfigOnly true',
|
|
123
|
+
'git config --unset user.name',
|
|
124
|
+
'git config --remove-section user',
|
|
125
|
+
'git config --remove-section-all user',
|
|
126
|
+
// Per the 2026-10-12 widening: every `git config` invocation is denied (read or write — the whole subcommand is closed; an agent that needs the current identity runs `git var GIT_AUTHOR_IDENT` or reads `.git/config` directly).
|
|
127
|
+
'git config --list',
|
|
128
|
+
'git config --list --local',
|
|
129
|
+
'git config --get user.name',
|
|
130
|
+
'git config --get-all user.email',
|
|
131
|
+
'git config --get-regexp "^user\\."',
|
|
132
|
+
'git config http.proxy http://proxy:8080',
|
|
133
|
+
'git config --global core.editor vim',
|
|
134
|
+
'git config --local init.defaultBranch main',
|
|
135
|
+
],
|
|
136
|
+
allow: [
|
|
137
|
+
// ordinary git traffic, no user.* anywhere
|
|
138
|
+
'git status',
|
|
139
|
+
'git log --oneline',
|
|
140
|
+
'git commit -m "ordinary commit"',
|
|
141
|
+
// help invocations are exempted (the only thing in `rest` is a flag)
|
|
142
|
+
'git -c user.name=Foo --help',
|
|
143
|
+
// other `-c` keys ride along freely (inline-override surface is the rule, not all `-c` flags)
|
|
144
|
+
'git -c http.proxy=http://proxy:8080 clone https://github.com/foo/bar',
|
|
145
|
+
'git -c core.autocrlf=false commit -m x',
|
|
146
|
+
'git -c init.defaultBranch=main init',
|
|
147
|
+
// The legitimate identity path: prefix every commit with `ADL_AGENT_ID_AGENT=agent-tarun` so the front controller stamps the right committer. This is what the rule tells the agent to do.
|
|
148
|
+
'ADL_AGENT_ID_AGENT=agent-tarun git commit -m "an agent commit"',
|
|
149
|
+
// The legitimate identity read: `git var GIT_AUTHOR_IDENT` (NOT `git config --get user.name`).
|
|
150
|
+
'git var GIT_AUTHOR_IDENT',
|
|
151
|
+
// `GIT_CONFIG_*` with no `user.*` key — not a user-override. Agents may legitimately override `http.proxy` or `init.defaultBranch` via the env-var form.
|
|
152
|
+
'GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.proxy GIT_CONFIG_VALUE_0=http://proxy:8080 git clone https://github.com/foo/bar',
|
|
153
|
+
'GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=init.defaultBranch GIT_CONFIG_VALUE_0=main git init',
|
|
154
|
+
// `GIT_CONFIG_KEY_<n>=user.*` with no COUNT or COUNT=0 — git ignores the key without a non-zero count, so this is a no-op and not a bypass.
|
|
155
|
+
'GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=Foo git commit -m x',
|
|
156
|
+
'GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0=user.name GIT_CONFIG_VALUE_0=Foo git commit -m x',
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
}
|
|
@@ -56,12 +56,12 @@ interface GatedCommand {
|
|
|
56
56
|
/**
|
|
57
57
|
* Only the flags a role rule actually inspects: `pr-create-or-update`'s
|
|
58
58
|
* `--action`/`--auto-complete`/`--no-auto-complete`/`--merge-strategy`/
|
|
59
|
-
* `--delete-source-branch` (`isPrCompletionCall`, pr-completion.ts)
|
|
59
|
+
* `--delete-source-branch` (`isPrCompletionCall`, pr-completion.ts),
|
|
60
60
|
* `pr-review`'s `--comment`/`--vote`/`--target-branch`
|
|
61
|
-
* (`adl-pr-review-role.ts`)
|
|
62
|
-
* graded on identity
|
|
63
|
-
*
|
|
64
|
-
* RECOGNIZED at all.
|
|
61
|
+
* (`adl-pr-review-role.ts`), and `build-run`'s `--id`/`--branch`
|
|
62
|
+
* (`adl.build-run-role`). `workitem-create-or-update` is graded on identity
|
|
63
|
+
* alone — no input field changes its outcome — so its flag list is empty;
|
|
64
|
+
* every command still needs an entry here so it is RECOGNIZED at all.
|
|
65
65
|
*/
|
|
66
66
|
const GATED_COMMANDS: Readonly<Record<string, GatedCommand>> = {
|
|
67
67
|
'workitem-create-or-update': { tool: 'workitem_create_or_update', flags: [] },
|
|
@@ -83,7 +83,13 @@ const GATED_COMMANDS: Readonly<Record<string, GatedCommand>> = {
|
|
|
83
83
|
{ flag: '--target-branch', key: 'targetBranch', type: 'string' },
|
|
84
84
|
],
|
|
85
85
|
},
|
|
86
|
-
'build-run': {
|
|
86
|
+
'build-run': {
|
|
87
|
+
tool: 'build_run',
|
|
88
|
+
flags: [
|
|
89
|
+
{ flag: '--id', key: 'id', type: 'integer' },
|
|
90
|
+
{ flag: '--branch', key: 'branch', type: 'string' },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
/**
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `adl.pr-complete-pending-decision` — docs/operations/agent-permissions.md row 9
|
|
3
|
-
* ("PR complete / set auto-complete"),
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* ("PR complete / set auto-complete"), DECIDED: denied for every identity —
|
|
4
|
+
* `agent-tarun`/`agent-vivek` AND `agent-reviewer` alike — as its own
|
|
5
|
+
* separately named rule specifically so the denial (or a future role split)
|
|
6
|
+
* can be relaxed without touching
|
|
7
7
|
* `adl.pr-create-update-role` (row 5), which keeps allowing a plain PR
|
|
8
8
|
* create/update for builders and `agent-reviewer` throughout
|
|
9
9
|
* (docs/specs/two-branch-standard-2026-09-27.md §1b.5: auto-complete is armed
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
* owner decision unrelated to this row, and denying that would block PR
|
|
17
17
|
* creation entirely).
|
|
18
18
|
*
|
|
19
|
-
* Deliberately does NOT require an identity to be present: row 9
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Deliberately does NOT require an identity to be present: row 9 denies
|
|
20
|
+
* EVERY identity, including a caller with no session identity at all
|
|
21
|
+
* (whichever rule reports first, the outcome is the same: denied).
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import type { Invocation } from '../shell/invocation.ts'
|
|
@@ -36,7 +36,7 @@ export const adlPrCompletePendingDecision: RuleSpec = {
|
|
|
36
36
|
severity: 'deny',
|
|
37
37
|
enabledByDefault: true,
|
|
38
38
|
summary:
|
|
39
|
-
'Deny PR completion / auto-complete for every identity
|
|
39
|
+
'Deny PR completion / auto-complete for every identity (docs/operations/agent-permissions.md row 9) — the MCP tool AND its adl mcp cli equivalent.',
|
|
40
40
|
params: noParams,
|
|
41
41
|
match(inv: Invocation): Finding | null {
|
|
42
42
|
// `adl mcp cli
|
|
@@ -54,7 +54,7 @@ export const adlPrCompletePendingDecision: RuleSpec = {
|
|
|
54
54
|
return {
|
|
55
55
|
user,
|
|
56
56
|
agent:
|
|
57
|
-
`DENIED ${user} (docs/operations/agent-permissions.md row 9
|
|
57
|
+
`DENIED ${user} (docs/operations/agent-permissions.md row 9: denied for every identity). Create or update the PR's title/description ` +
|
|
58
58
|
`normally; do not pass autoComplete, mergeStrategy, or deleteSourceBranch. Blocked: ${ctx.snippet}`,
|
|
59
59
|
}
|
|
60
60
|
},
|
|
@@ -34,11 +34,12 @@
|
|
|
34
34
|
* regardless of who is asking, and the two rules never fight over the same
|
|
35
35
|
* call.
|
|
36
36
|
*
|
|
37
|
-
* Rows 6
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* Rows 6-8 (PR comment; PR vote on `main`; PR vote on `integration`) ship
|
|
38
|
+
* their own gate now: the sibling `adl-pr-review-role.ts` rules
|
|
39
|
+
* `pr_review` (shipped in `packages/azdo/src/azdo-pr-review.ts`, C3
|
|
40
|
+
* 2026-09-27) — comment allowed for the same allow-set as row 5, vote
|
|
41
|
+
* allowed for `agent-reviewer` only and only on `main`. This rule does not
|
|
42
|
+
* match `pr_review` at all; the two rules never fight over the same call.
|
|
42
43
|
*
|
|
43
44
|
* Requires an identity to already be present (`ADL_AGENT_ID_AGENT`
|
|
44
45
|
* non-blank) — with no identity at all, `adl.run-required-for-writes`
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
* Editing the files that wire the host's hooks.
|
|
3
3
|
*
|
|
4
4
|
* Handoff 5, rule 5: deny Write/Edit/MultiEdit/NotebookEdit on
|
|
5
|
-
* `.claude/settings.json`, `.claude/settings.local.json`,
|
|
6
|
-
* `.codex/config.toml`. These are the files that
|
|
7
|
-
* host (including the `.local.json` overrides)
|
|
8
|
-
*
|
|
5
|
+
* `.claude/settings.json`, `.claude/settings.local.json`,
|
|
6
|
+
* `.codex/config.toml`, or `adl-config.toml`. These are the files that
|
|
7
|
+
* install the hook into the host (including the `.local.json` overrides)
|
|
8
|
+
* or that the running hook reads on every call — editing any of them is a
|
|
9
|
+
* way to switch the gate off without anyone noticing.
|
|
9
10
|
*
|
|
10
|
-
* `adl-config.toml`
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* below are only as strong as that file,
|
|
19
|
-
* off.
|
|
11
|
+
* `adl-config.toml` left the list on 2026-10-01 (Tarun: "nobody should
|
|
12
|
+
* stop editing adl-config.toml") and rejoined it on 2026-10-12, after a
|
|
13
|
+
* review-of-the-door confirmed the gap: every hook run re-reads it, so
|
|
14
|
+
* `[hooks] enabled = false` (a silent no-op, `main.ts`'s `runHook`) or a
|
|
15
|
+
* `[rules."<id>"] enabled = false` takes effect on the agent's next tool
|
|
16
|
+
* call, ahead of any commit. The commit-time layers
|
|
17
|
+
* (`git.protected-tree-commit`, repo-controls' integrity gate) fire on the
|
|
18
|
+
* COMMITTED file, not on the working-tree copy that the running hook
|
|
19
|
+
* reads. The carriers on the list below are only as strong as that file,
|
|
20
|
+
* since it can also switch THIS rule off.
|
|
20
21
|
*
|
|
21
22
|
* Hooks are local-repo-first (Tarun, 2026-09-29): there is no managed-hooks
|
|
22
23
|
* lock and no global carrier, so these per-repo carrier files are the ONLY
|
|
@@ -49,10 +49,9 @@ export const gitHooksPath: RuleSpec = {
|
|
|
49
49
|
'git -c core.hooksPath=/dev/null commit -m x',
|
|
50
50
|
'git -c core.hooksPath= push',
|
|
51
51
|
'git -c core.hooksPath=/tmp/empty commit --amend',
|
|
52
|
-
'git config core.hooksPath /dev/null',
|
|
53
|
-
'git config --global core.hooksPath /tmp/empty',
|
|
54
52
|
],
|
|
55
|
-
|
|
53
|
+
// The `git config core.hooksPath …` positive controls were here for years — gone as of Bug 695 (2026-10-12): `adl.git-user-override-block` denies every `git config` invocation in the engine, so a `git config …` string is denied upstream and never exercises the `subcommand === 'config' && overridesHooksPath(git.rest)` branch (the `-c` deny entries above still cover the override surface).
|
|
54
|
+
allow: ['git stash --help'],
|
|
56
55
|
},
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -91,11 +90,8 @@ export const gitCoreBare: RuleSpec = {
|
|
|
91
90
|
deny: [
|
|
92
91
|
'git -c core.bare=true status',
|
|
93
92
|
'git -c core.bare=false commit -m x',
|
|
94
|
-
'git config core.bare true',
|
|
95
|
-
'git config --bool core.bare true',
|
|
96
|
-
'git config --global core.bare true',
|
|
97
|
-
'git config --unset core.bare',
|
|
98
93
|
],
|
|
99
|
-
|
|
94
|
+
// The `git config core.bare …` positive controls were here for years — gone as of Bug 695 (2026-10-12): `adl.git-user-override-block` denies every `git config` invocation in the engine, so a `git config …` string is denied upstream and never exercises the `subcommand === 'config' && flipsCoreBare(git.rest)` branch (the `-c` deny entries above still cover the override surface).
|
|
95
|
+
allow: ['git status'],
|
|
100
96
|
},
|
|
101
97
|
}
|
|
@@ -50,7 +50,7 @@ export function toolNameEndingWithKnownSuffix(tool: string, knownSuffixes: Reado
|
|
|
50
50
|
*
|
|
51
51
|
* Shared by every rule that gates an Azure DevOps MCP tool by name
|
|
52
52
|
* (adl-run-required.ts, adl-pr-role.ts, adl-pr-complete-pending.ts,
|
|
53
|
-
* adl-workitem-role.ts, adl-build-run-
|
|
53
|
+
* adl-workitem-role.ts, adl-build-run-role.ts) so the parsing cannot drift
|
|
54
54
|
* between them.
|
|
55
55
|
*
|
|
56
56
|
* Prefix-less fallback (added 2026-09-28 with the one-agent-identity
|
|
@@ -56,13 +56,13 @@ export const toolNativeSearch: RuleSpec = {
|
|
|
56
56
|
category: 'tool-call',
|
|
57
57
|
severity: 'deny',
|
|
58
58
|
enabledByDefault: true,
|
|
59
|
-
summary: 'Deny the native Grep/Glob/Search tools; steer at search <semantic query | keywords> (
|
|
59
|
+
summary: 'Deny the native Grep/Glob/Search tools; steer at search <semantic query | keywords> (markdown), crg (code graph), rg, ast-grep.',
|
|
60
60
|
params: noParams,
|
|
61
61
|
match(inv: Invocation): Finding | null {
|
|
62
62
|
if (inv.kind !== 'tool-call') return null
|
|
63
63
|
if (!new Set(loadSurfacePolicy().deny.nativeTools).has(inv.tool)) return null
|
|
64
64
|
// Surface the tool input's path-ish field for the message so it can
|
|
65
|
-
// recommend `search` (the right tool for
|
|
65
|
+
// recommend `search` (the right tool for markdown) over
|
|
66
66
|
// `crg` (the right tool for code-graph queries). Different hosts name
|
|
67
67
|
// this field differently — Claude uses `path`, Codex uses `path`,
|
|
68
68
|
// Cursor uses `target_file` / `target_directory` for Write. The
|
|
@@ -77,10 +77,11 @@ export const toolNativeSearch: RuleSpec = {
|
|
|
77
77
|
},
|
|
78
78
|
message(finding: Finding, ctx: MessageContext) {
|
|
79
79
|
const tool = typeof finding.detail.tool === 'string' ? finding.detail.tool : 'this tool'
|
|
80
|
-
// Path-aware recommendation. Native Grep on
|
|
81
|
-
//
|
|
80
|
+
// Path-aware recommendation. Native Grep on a markdown file (any
|
|
81
|
+
// docs/plans/.scratchpad tree or *.md path) -> lead with `search`;
|
|
82
|
+
// code -> lead with `crg`.
|
|
82
83
|
const path = typeof finding.detail.path === 'string' ? finding.detail.path : ''
|
|
83
|
-
const isDoc = DOC_TREES.some((prefix) => path.startsWith(prefix))
|
|
84
|
+
const isDoc = DOC_TREES.some((prefix) => path.startsWith(prefix)) || path.endsWith('.md')
|
|
84
85
|
|
|
85
86
|
const leadTool = isDoc ? 'search' : 'crg'
|
|
86
87
|
const leadExamples = ALLOWED_SEARCH_TOOLS.find((row) => row.binary === leadTool)?.examples ?? []
|
|
@@ -93,8 +94,8 @@ export const toolNativeSearch: RuleSpec = {
|
|
|
93
94
|
|
|
94
95
|
return {
|
|
95
96
|
user: isDoc
|
|
96
|
-
? `Blocked the native ${tool} tool on \`${path}\` (
|
|
97
|
-
: `Blocked the native ${tool} tool. Lead with \`crg search "<text>"\` for code-graph queries, fall back to \`rg\`/\`ast-grep\` for literal text, \`search <semantic query | keywords>\`
|
|
97
|
+
? `Blocked the native ${tool} tool on \`${path}\` (markdown). The right answer is \`search <semantic query | keywords>\` — semantic + keyword, finds the doc that *talks* about X, in any markdown file. \`rg\`/\`crg\` are the wrong tools here.`
|
|
98
|
+
: `Blocked the native ${tool} tool. Lead with \`crg search "<text>"\` for code-graph queries, fall back to \`rg\`/\`ast-grep\` for literal text, \`search <semantic query | keywords>\` for any markdown file.`,
|
|
98
99
|
agent:
|
|
99
100
|
`DENIED the native ${tool} tool. It is routed through the lean-ctx hook but NOT converted — ` +
|
|
100
101
|
'the call still runs natively — so it is a way around the shell search ban rather than an ' +
|
|
@@ -25,6 +25,7 @@ import type { AnyRuleSpec, RuleId } from './spec.ts'
|
|
|
25
25
|
import { asAnyRuleSpec, corpusIsEmpty } from './spec.ts'
|
|
26
26
|
|
|
27
27
|
import { gitHooksPath, gitCoreBare } from './impl/git-core.ts'
|
|
28
|
+
import { adlGitUserOverrideBlock } from './impl/adl-git-user-override-block.ts'
|
|
28
29
|
import { gitStash, gitClean, gitRebase, gitFilterBranch, gitRestore, gitReset, gitUpdateIndex } from './impl/git-transitions.ts'
|
|
29
30
|
import { gitNoVerify, gitAmend } from './impl/git-verify.ts'
|
|
30
31
|
import { gitProtectedTreeCommit } from './impl/git-protected-tree.ts'
|
|
@@ -63,7 +64,7 @@ import { adlPrCreateUpdateRole } from './impl/adl-pr-role.ts'
|
|
|
63
64
|
import { adlPrReviewRole } from './impl/adl-pr-review-role.ts'
|
|
64
65
|
import { adlPrCompletePendingDecision } from './impl/adl-pr-complete-pending.ts'
|
|
65
66
|
import { adlWorkitemRequiresTarunOrVivek } from './impl/adl-workitem-role.ts'
|
|
66
|
-
import {
|
|
67
|
+
import { adlBuildRunRole } from './impl/adl-build-run-role.ts'
|
|
67
68
|
import { toolFind } from './impl/tool-find.ts'
|
|
68
69
|
import { toolGrep } from './impl/tool-grep.ts'
|
|
69
70
|
import { toolNativeSearch } from './impl/tool-native-search.ts'
|
|
@@ -85,6 +86,14 @@ import { agentTamperProtection } from './impl/agent-tamper-protection.ts'
|
|
|
85
86
|
export const GIT_RULES: readonly AnyRuleSpec[] = [
|
|
86
87
|
gitHooksPath,
|
|
87
88
|
gitCoreBare,
|
|
89
|
+
// Right after the `core.*` override rules: a `user.*` override rides
|
|
90
|
+
// along with any subcommand via `-c user.*=`, exactly the way
|
|
91
|
+
// `core.hooksPath` / `core.bare` do — a `git -c user.name=human commit`
|
|
92
|
+
// / `push` should be reported as the user override, not whatever
|
|
93
|
+
// commit/push policy would otherwise report. The user's call (2026-10-12)
|
|
94
|
+
// is "no use of git -c user* at all … blanket ban for agents"; see
|
|
95
|
+
// CONTRIBUTING.md line 18 and INVARIANTS.md line 55.
|
|
96
|
+
adlGitUserOverrideBlock,
|
|
88
97
|
gitStash,
|
|
89
98
|
gitClean,
|
|
90
99
|
gitRebase,
|
|
@@ -150,7 +159,7 @@ export const TOOL_RULES: readonly AnyRuleSpec[] = [
|
|
|
150
159
|
adlPrReviewRole,
|
|
151
160
|
adlPrCompletePendingDecision,
|
|
152
161
|
adlWorkitemRequiresTarunOrVivek,
|
|
153
|
-
|
|
162
|
+
adlBuildRunRole,
|
|
154
163
|
].map(
|
|
155
164
|
asAnyRuleSpec,
|
|
156
165
|
)
|
|
@@ -29,10 +29,14 @@ export const PROTECTED_CARRIER_PATHS: ReadonlySet<string> = new Set([
|
|
|
29
29
|
'.claude/settings.json',
|
|
30
30
|
'.claude/settings.local.json',
|
|
31
31
|
'.codex/config.toml',
|
|
32
|
-
// `adl-config.toml`
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
32
|
+
// `adl-config.toml` is the repo's hook switch — every hook run re-reads it,
|
|
33
|
+
// so an agent that writes `[hooks] enabled = false` or disables any rule
|
|
34
|
+
// flips the gate off before the next tool call lands. Re-listed here on
|
|
35
|
+
// 2026-10-12 (Tarun: "we left a door open, close it"). The earlier
|
|
36
|
+
// 'human-only at commit time' assumption was wrong: the commit-time gate
|
|
37
|
+
// fires for the COMMITTED file, not for edits that never stage, and the
|
|
38
|
+
// working-tree copy is what every running hook reads.
|
|
39
|
+
'adl-config.toml',
|
|
36
40
|
'.codex/hooks.json',
|
|
37
41
|
'.cursor/hooks.json',
|
|
38
42
|
'.opencode/plugins/adl-repo.ts',
|
|
@@ -142,7 +146,7 @@ const PROTECTED_CARRIER_DIRS: ReadonlySet<string> = new Set([
|
|
|
142
146
|
*
|
|
143
147
|
* `path` ending in a literal
|
|
144
148
|
* `/` (BEFORE normalization strips it for the comparison itself) means "a
|
|
145
|
-
* file goes INTO this directory" (`cp GLOBAL-AGENTS.md .claude/`, `mv
|
|
149
|
+
* file goes INTO this directory" (`cp TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md .claude/`, `mv
|
|
146
150
|
* notes.md .cursor/`) — the directory itself is untouched, only gaining an
|
|
147
151
|
* unrelated file — never "this directory is the thing being moved/
|
|
148
152
|
* overwritten" (`mv .claude .claude-old`, `mv attacker-stuff .codex` — no
|
|
@@ -90,7 +90,7 @@ the built-in target allowlist.
|
|
|
90
90
|
Ownership rule: machine-global agent configuration belongs to enact-vps;
|
|
91
91
|
everything else belongs in the owning repository. The sweep therefore treats
|
|
92
92
|
anything not declared by enact-vps (`protected.json`, the Kimi managed block,
|
|
93
|
-
|
|
93
|
+
global-agents deployment targets) as foreign:
|
|
94
94
|
|
|
95
95
|
- JSON entries: Claude `settings.json` `hooks`, `mcpServers`, `enabledPlugins`,
|
|
96
96
|
`extraKnownMarketplaces`, `permissions.allow|deny|ask` items; `.claude.json`
|
|
@@ -239,13 +239,13 @@ purpose even though it is a real, documented key, so the whole container
|
|
|
239
239
|
stays a sweep candidate whenever non-empty — see the `reason` field on that
|
|
240
240
|
baseline entry for the specific rationale.
|
|
241
241
|
|
|
242
|
-
## Global agent instructions (`GLOBAL-AGENTS.md`)
|
|
242
|
+
## Global agent instructions (`TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md`)
|
|
243
243
|
|
|
244
|
-
[`GLOBAL-AGENTS.md`](./assets/GLOBAL-AGENTS.md) is the single source of truth for
|
|
244
|
+
[`TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md`](./assets/TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md) is the single source of truth for
|
|
245
245
|
every host's global instruction file: `~/.claude/CLAUDE.md`,
|
|
246
246
|
`~/.codex/AGENTS.md`, `~/.cursor/AGENTS.md`, `~/.kimi-code/AGENTS.md`, and
|
|
247
247
|
`~/.config/opencode/AGENTS.md`. Any change to those files must be made in
|
|
248
|
-
`GLOBAL-AGENTS.md`; a direct edit to a target is drift and is overwritten on
|
|
248
|
+
`TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md`; a direct edit to a target is drift and is overwritten on
|
|
249
249
|
the next deploy.
|
|
250
250
|
|
|
251
251
|
```bash
|
|
@@ -254,6 +254,12 @@ bin/global-agents --home "$HOME" --mode deploy # forced
|
|
|
254
254
|
bin/global-agents --home "$HOME" --mode uninstall
|
|
255
255
|
```
|
|
256
256
|
|
|
257
|
+
Deploy and status run only on Tarun's fleet (Tarun, 2026-10-10): the device
|
|
258
|
+
name is the first label of the hostname (or `--host NAME`), and it must be a
|
|
259
|
+
`mac.devices` or `linux.devices` key in `packages/fleet/manifest.json`.
|
|
260
|
+
Any other machine writes no global file and prints one `skipped:` line saying
|
|
261
|
+
why; existing files there are left alone, and uninstall is not gated.
|
|
262
|
+
|
|
257
263
|
Deploy is always forced; there is no `--force` flag and no leave-in-place
|
|
258
264
|
mode. A missing target is created, a target already equal to the source is
|
|
259
265
|
left untouched, and a drifted target (hand-edited, or stale from an older
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Tarun's global agent instructions
|
|
2
|
+
|
|
3
|
+
My personal preferences, for every agent on every machine I own, for coding and non-coding work alike.
|
|
4
|
+
Where a repository has its own AGENTS.md, that file and the files it links add the repository's rules. They never relax Truthfulness, Verification before claiming done or Scope discipline here; on any other conflict, ask.
|
|
5
|
+
|
|
6
|
+
## Communication
|
|
7
|
+
- Address me as **Tarun**.
|
|
8
|
+
- **Answer first.** No greeting, no "let me", no recap of what was just done, no closers.
|
|
9
|
+
- One idea per sentence. Short beats polite. Articles can go; not, never, no, only never do. Numbers, paths, commands exact.
|
|
10
|
+
- Bullet points over prose.
|
|
11
|
+
- **Open points:** one numbered list of open decisions per conversation. Show it only when it changes — item added or resolved. After a long gap or compaction, restate the full list. That is when it gets lost.
|
|
12
|
+
- **Questions:** one at a time, one or two sentences. Options inline: `A) … B) …`. A long multi-part question means split the work, not more prose.
|
|
13
|
+
- Full sentences for security warnings, irreversible actions, step-by-step orders, and when I'm confused. Then short resumes.
|
|
14
|
+
- No performance. If short phrasing isn't shorter, plain English wins. Never rewrite my prompts.
|
|
15
|
+
|
|
16
|
+
## Truthfulness (non-negotiable)
|
|
17
|
+
- Never present something as done, working or checked when it is not. A failure reported plainly is worth more than a success that is not real.
|
|
18
|
+
- **No silent fallback or degrade** — if the real path fails, say so loudly and stop.
|
|
19
|
+
- **No silent drops** — no skipped steps, ignored errors or quietly narrowed scope.
|
|
20
|
+
- **No fakes** — no placeholders, stand-ins or TODOs passed off as finished.
|
|
21
|
+
- Unverified claims never enter anything that lasts: documents, messages, notes, memory.
|
|
22
|
+
- Never read secret stores or credential files, never pass a token or password in a command or message, and never claim to be me or set anything that marks the session as human (drafting in my name when I ask is fine).
|
|
23
|
+
|
|
24
|
+
## Verification before claiming done
|
|
25
|
+
- **Evidence over assertions:** show what you ran or read, and make the check falsifiable ("did you search the source?" has an answer; "did you verify?" does not).
|
|
26
|
+
- **A search shows what was returned, not what exists.** Before saying something is absent, say how you looked, and run a control search the same way for something you know is there. Search wide first, then narrow. No hits for both means you searched the wrong place.
|
|
27
|
+
- **Ask the authoritative source, not the one in front of you:** the original over a copy, the live system over a description of it.
|
|
28
|
+
- **Re-check before reporting.** Cite the check you are reporting, not one you remember. Never claim "checked everything" without checking every case.
|
|
29
|
+
- A requirement you are about to not meet is a **stop**: tell me; never quietly decide to skip it.
|
|
30
|
+
|
|
31
|
+
## Scope discipline
|
|
32
|
+
- Work in your own working directory. Touch only what is in scope: the files, accounts, people and systems the task names.
|
|
33
|
+
- Anything outside scope is raised as an open point for me (or recorded where that work is tracked): never silently done, never silently dropped.
|
|
34
|
+
|
|
35
|
+
## Delegation & parallelism
|
|
36
|
+
- Where the surface supports helper agents, the main agent orchestrates and verifies and helpers do the hands-on work; small tasks may be done directly.
|
|
37
|
+
- Split independent work into **concurrent agents** launched together — never sequential when it can fan out.
|
|
38
|
+
- Match the model to the task: strongest for deep analysis and judgment, fastest for quick lookups.
|
|
39
|
+
- Author and reviewer are **distinct passes in separate contexts**. Never self-approve.
|
|
40
|
+
- Prefer speed through parallel runs and fast models; never skip verification for speed.
|