brindle 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {brindle-0.3.1 → brindle-0.3.3}/PKG-INFO +112 -2
- {brindle-0.3.1 → brindle-0.3.3}/README.md +111 -1
- {brindle-0.3.1 → brindle-0.3.3}/pyproject.toml +1 -1
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/agents.py +190 -47
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/antigravity.py +111 -20
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/autopilot.py +17 -2
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/ci_client.py +2 -3
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/cli.py +42 -9
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/codex_hook.py +22 -4
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/config.py +11 -3
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/db.py +18 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/doctor.py +24 -0
- brindle-0.3.3/src/brindle/launch_health.py +379 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/model_access.py +34 -11
- brindle-0.3.3/src/brindle/model_availability.py +504 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/runner.py +2 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/permissions.py +188 -4
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/account.py +6 -1
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/auth.py +1 -1
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/providers.py +129 -15
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/repos.py +5 -1
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/tmux.py +22 -0
- {brindle-0.3.1 → brindle-0.3.3}/.gitignore +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/LICENSE +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/SCHEDULE-A +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/__init__.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/__main__.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/account.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/airgap.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/budget.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/__init__.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/backend-auditor.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/developer-codex.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/developer-heavy.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/developer-light.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/developer-local.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/developer.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/qa.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/reviewer-codex.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/reviewer-local.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/reviewer.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/subagent.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_agents/supervisor.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_rules/__init__.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_rules/security/backend.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_rules/style/minimal-diff.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/builtin_rules/tests/only.md +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/ci_adapters.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/ci_federation.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/ci_hosts.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/codemap.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/company_identity.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/company_login.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/conflicts.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/cost.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/cost_estimate.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/cull.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/demo.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/detect.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/escapes.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/events.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/gates.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/git.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/guardrails.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/history.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/identity_lock.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/inbox.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/keys_cmds.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/keystore.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/learned_rules.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/learning.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/legacy.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/mcp_server.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/__init__.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/client.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/loop.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/permissions.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/serve.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/native/tools.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pane_auth.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pipeline.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/plugins.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/policy.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pool.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pricing.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/__init__.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/_files.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/audit_chain.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/audit_export.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/brief_learning.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/cost_centers.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/credentials.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/features.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/keys.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/learning.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/license.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/loopback.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/managed_models.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/org_profiles.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/orgkey.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/rollout.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/settings_sync.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/status.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/team_events.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/pro/team_policy.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/procs.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/profiles.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/quota.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/repo_cmds.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/rewind.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/rule_checks.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/savings.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/scratch.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/secrets.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/self_serve.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/services.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/sessions.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/sidebar_follow.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/signin_pause.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/status_cache.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/tasks.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/usage.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/view.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/watch.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/watch_costs.py +0 -0
- {brindle-0.3.1 → brindle-0.3.3}/src/brindle/workspaces.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brindle
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Run coding agents in parallel, each on its own git branch, with a supervisor that delegates, reviews, and merges
|
|
5
5
|
Project-URL: Homepage, https://pawdelta.com/brindle/
|
|
6
6
|
Project-URL: Documentation, https://pawdelta.com/brindle/docs/recommended-use
|
|
@@ -89,7 +89,7 @@ uv tool install --editable ~/Projects/brindle # or from a local checkout
|
|
|
89
89
|
brindle drives Claude Code, so you need that too (`npm install -g @anthropic-ai/claude-code`).
|
|
90
90
|
|
|
91
91
|
`brindle --version` prints the installed version; the tmux status bar of every brindle
|
|
92
|
-
session shows it too (`brindle 0.3.
|
|
92
|
+
session shows it too (`brindle 0.3.3`). A session started before an upgrade keeps
|
|
93
93
|
running the old code, and shows the old number, until you restart it.
|
|
94
94
|
|
|
95
95
|
## Quick start
|
|
@@ -539,6 +539,7 @@ Autopilot, merge gates and cleanup:
|
|
|
539
539
|
| `merge_into` | none | branch that worker branches are cut from and merge into, whatever branch the supervisor is on |
|
|
540
540
|
| `auto_merge_default_branch` | `false` | let the pipeline merge into the repo's default branch (origin HEAD, else `main`/`master`) on its own; by default it sends a "needs you" message instead, and you run `merge_workspace` yourself (manual merges are never gated) |
|
|
541
541
|
| `permission_policy` | `"off"` | `"on"`: brindle answers Claude Code workers' permission prompts from its rules (see "Permission policy" below); off, the prompts behave as they always did |
|
|
542
|
+
| `agy_approvals` | `"prompt"` | `"brindle"`: with the policy on, Antigravity workers run without approval prompts and brindle's hook allows or denies every call (see "Antigravity" under "Permission policy") |
|
|
542
543
|
| `rules` | `[]` | standing rules for the supervisor, e.g. `["Fix review findings without asking", "Validate options before offering them"]`; added to every supervisor's brief. Rules in `~/.brindle/config.json`, the repo's config and `config.local.json` are all kept, so a team's rules and your own add up |
|
|
543
544
|
| `plan_first` | `false` | workers propose a plan (`submit_plan`) and wait for `approve_plan` before editing |
|
|
544
545
|
| `overlap` | `"block"` | a task whose `files` overlap a running task's is refused (`"warn"` starts it with a warning) |
|
|
@@ -602,6 +603,21 @@ keep theirs):
|
|
|
602
603
|
No tier prefers another provider for its own sake: all-Claude or all-Codex may
|
|
603
604
|
be what works best for you, and that's for the learner to find out.
|
|
604
605
|
|
|
606
|
+
Routing merges per tier in this order: built-in defaults, `~/.brindle/config.json`
|
|
607
|
+
(every repo), the repo's `.brindle/config.json` (shared with the team), then
|
|
608
|
+
`.brindle/config.local.json` (your override for that repo). Each tier you set
|
|
609
|
+
replaces that tier's list; tiers you leave out keep the list from the layer below.
|
|
610
|
+
For example, put this in `~/.brindle/config.json` to use Codex for light tasks
|
|
611
|
+
in every repo, or in a repo's `.brindle/config.local.json` to do so only there:
|
|
612
|
+
|
|
613
|
+
```json
|
|
614
|
+
{"routing": {"light": ["developer-codex", "developer"]}}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
Run `brindle doctor` in the repo to see the effective list and source file for
|
|
618
|
+
each tier. Unknown profile names are skipped; doctor and the routing reply
|
|
619
|
+
report the missing name and the file that supplied it.
|
|
620
|
+
|
|
605
621
|
`developer-light` runs on Claude Haiku at low effort; `developer` on your Claude
|
|
606
622
|
Code default model; `developer-codex` on Codex; `developer-heavy` on Claude Fable
|
|
607
623
|
at high effort.
|
|
@@ -612,6 +628,53 @@ wins. When every candidate is out, the repo's `default_agent` runs. The reply sa
|
|
|
612
628
|
what was picked and why, e.g. `weight medium -> developer (Codex at 93%, skipped developer-codex)`.
|
|
613
629
|
An `agent_profile` you pass, or a milestone's `profile`, always wins over weight.
|
|
614
630
|
|
|
631
|
+
Provisioning and routing also check explicit models against supported read-only
|
|
632
|
+
catalogs, with the managed model, stored keys and the worker's filtered pane
|
|
633
|
+
environment. A model absent from a complete authoritative catalog is rejected
|
|
634
|
+
before creating a worker worktree or process. Partial catalogs, aliases,
|
|
635
|
+
discovery errors and Codex's bundled catalogs remain unverified; being listed
|
|
636
|
+
does not prove generation access, billing or quota. Catalog discovery is bounded
|
|
637
|
+
to five seconds for standalone checks; foreground routing/provisioning limits
|
|
638
|
+
discovery to one second, leaving room in the three-second launch budget for
|
|
639
|
+
provisioning and bounded helper cleanup. A timeout remains unverified and
|
|
640
|
+
launch proceeds with the real-task health follow-up. Catalogs are cached
|
|
641
|
+
briefly by environment and local account/config
|
|
642
|
+
revision where available. Routing and provisioning reuse equivalent catalog
|
|
643
|
+
context across worktrees, excluding launch bookkeeping while retaining project
|
|
644
|
+
settings, credentials and account selectors. CLI catalogs remain advisory;
|
|
645
|
+
unobservable external/keychain login changes may remain cached for 30 seconds.
|
|
646
|
+
Custom CLI binaries retain separate cache entries per working directory.
|
|
647
|
+
Claude, Bedrock, Vertex and Foundry have no catalog
|
|
648
|
+
probe here; no Claude CLI or synthetic generation request is used for these checks.
|
|
649
|
+
|
|
650
|
+
The real first worker task is sent once. A detached helper inspects its current
|
|
651
|
+
pane five seconds after delivery, so readiness delays do not use up that window.
|
|
652
|
+
Fresh interactive Antigravity chats without a task still receive their profile,
|
|
653
|
+
tool instructions and any autopilot context once after readiness; worker
|
|
654
|
+
instructions accompany the actual task in the same delivery.
|
|
655
|
+
For argv tasks, the timer starts at prompt submission or observed CLI readiness,
|
|
656
|
+
after trust/startup handling; readiness timeout does not establish delivery or
|
|
657
|
+
release queued work. Paused workers, replaced launches and reassigned panes are
|
|
658
|
+
excluded from the observation.
|
|
659
|
+
Explicit fresh authentication, access, model and capacity errors, or an early
|
|
660
|
+
exit, produce a safe supervisor message with a next step. A live process with
|
|
661
|
+
no clear result is recorded as pending for diagnostics, not verified model
|
|
662
|
+
access; it does not send a supervisor notification. Refusals use
|
|
663
|
+
the existing one-hour cooldown, scoped to the effective model/environment and
|
|
664
|
+
local login revision. Changing the account, model or credentials invalidates
|
|
665
|
+
that refusal; CLI/keychain account changes without an observable local revision
|
|
666
|
+
may require waiting for the cooldown or clearing `model_refusals.json`.
|
|
667
|
+
This is a single observation, not an entitlement test: unfamiliar error layouts,
|
|
668
|
+
later failures and slow requests can remain pending. It does not scan
|
|
669
|
+
historical transcripts, and excludes task text, previous pane lines and older
|
|
670
|
+
marked replies, fenced examples and ordinary assistant/tool explanations. A
|
|
671
|
+
Codex follow-up retains the complete submitted argv prompt (including profile
|
|
672
|
+
instructions) and distinguishes assistant/tool responses from the idle composer.
|
|
673
|
+
Quoted prompts and error-looking markers inside assistant/tool output remain
|
|
674
|
+
ambiguous and pending; markers from another provider do not establish failure.
|
|
675
|
+
A separate detached check covers headless and argv startup exits before task
|
|
676
|
+
delivery. Existing readiness and watch/cull handling continues afterward.
|
|
677
|
+
|
|
615
678
|
**Hosted learning (brindle Pro).** With a plan that includes it, brindle learns
|
|
616
679
|
which of your `learning_candidates` profiles suits which kind of task, and picks
|
|
617
680
|
one when `assign` gets no profile and no milestone names one (the reply says
|
|
@@ -710,6 +773,38 @@ Codex patches are checked file by file: allowed only if every file is. Codex
|
|
|
710
773
|
doesn't say which tool run followed which prompt, so brindle doesn't learn from
|
|
711
774
|
Codex approvals. To undo, delete that entry (or untrust it in Codex's `/hooks`).
|
|
712
775
|
|
|
776
|
+
Codex also uses the profile's `allowed_tools` shell entries: `Bash(just lint)`
|
|
777
|
+
allows that exact command, and `Bash(task test:*)` allows it with arguments.
|
|
778
|
+
The same simple-command restriction applies, and default, user, repo and
|
|
779
|
+
profile denies still win. Other `allowed_tools` entries aren't translated.
|
|
780
|
+
An unrecognized patch header prevents automatic approval without discarding
|
|
781
|
+
denies for files brindle can identify. Session/status bookkeeping failures
|
|
782
|
+
don't discard the hook's decision; failures to evaluate the policy leave
|
|
783
|
+
Codex's normal approval flow in place.
|
|
784
|
+
|
|
785
|
+
Scope and platform limits: this is an **approval-request hook**, not a gate
|
|
786
|
+
on every tool call. Codex commands already permitted by its sandbox or own
|
|
787
|
+
rules never reach it, so brindle cannot enforce denies on those calls. It
|
|
788
|
+
doesn't change Codex's sandbox or approval mode, and cannot make a `never`
|
|
789
|
+
approval mode interactive. Disabled hooks, managed-only hook policies, older
|
|
790
|
+
Codex versions without `PermissionRequest`, and nonlocal execution can prevent
|
|
791
|
+
the hook from running. Keep Codex's own restrictions for tools that must always
|
|
792
|
+
be blocked. See the [OpenAI hook protocol](https://learn.chatgpt.com/docs/hooks).
|
|
793
|
+
|
|
794
|
+
The integration targets local macOS/Linux Codex CLI processes (POSIX shell
|
|
795
|
+
quoting); native Windows hook commands aren't supported. The local app-server
|
|
796
|
+
protocol was checked on macOS with Codex CLI **0.162.1**: newline-delimited
|
|
797
|
+
`initialize`, `initialized`, and `hooks/list` returned the session-flags key
|
|
798
|
+
above, `eventName: "permissionRequest"`, `source: "sessionFlags"`,
|
|
799
|
+
`currentHash`, `enabled: true`, and `trustStatus: "trusted"` for the installed
|
|
800
|
+
brindle hook. This read-only probe made no model calls or trust edits; hook
|
|
801
|
+
dispatch/allow/deny behavior is covered by the permission tests. Linux runtime
|
|
802
|
+
and native Windows behavior were not exercised by that probe.
|
|
803
|
+
`codex features list` also reported `hooks stable true` without a user
|
|
804
|
+
`features.hooks` setting, both on 0.162.1 and the bundled 0.158.0-alpha.2.1.
|
|
805
|
+
A session override of `features.hooks=false` reported false. No feature-enable
|
|
806
|
+
flag is needed on these versions, and brindle leaves explicit disablement alone.
|
|
807
|
+
|
|
713
808
|
**Antigravity.** agy's hook can deny but its "allow" is ignored (an agy bug),
|
|
714
809
|
and it has no "no opinion" answer. So the hook denies what the policy denies,
|
|
715
810
|
answers "allow" for a file inside the workspace (which agy reads and writes
|
|
@@ -726,6 +821,21 @@ does it by hand. To undo, turn `permission_policy` off and run `sync-agy`: brind
|
|
|
726
821
|
removes exactly its own entries. brindle doesn't learn from agy approvals (its
|
|
727
822
|
hook runs for every tool call, so a tool running doesn't mean you approved it).
|
|
728
823
|
|
|
824
|
+
With `"agy_approvals": "brindle"` (and the policy on), brindle's hook is the
|
|
825
|
+
only gate instead: agy workers start with `--dangerously-skip-permissions`,
|
|
826
|
+
under which agy still honors a hook's deny, and the hook runs on every tool,
|
|
827
|
+
subagents' calls included. It allows what a rule allows (a repo's checks
|
|
828
|
+
included), the shell commands in the profile's `allowed_tools` (what a Claude
|
|
829
|
+
Code worker on it runs without asking), files inside the workspace given as one
|
|
830
|
+
absolute path (writes under `.agents/`, `.git/` and
|
|
831
|
+
`.brindle/` only by a rule, since those hold the hook, git's hooks and the
|
|
832
|
+
repo's checks), brindle's own tools and agy's tools that act only on the
|
|
833
|
+
conversation, and denies everything else, telling the agent to
|
|
834
|
+
ask its supervisor; you allow it with `brindle permissions allow`. Any failure
|
|
835
|
+
in the hook is a deny, and a tool brindle doesn't know is denied. Nobody can
|
|
836
|
+
approve a prompt in the agent's pane in this mode. The default, `"prompt"`,
|
|
837
|
+
leaves agy asking as described above.
|
|
838
|
+
|
|
729
839
|
## brindle Pro and Team
|
|
730
840
|
|
|
731
841
|
brindle is complete on its own. brindle Pro adds hosted learning (which profile
|
|
@@ -59,7 +59,7 @@ uv tool install --editable ~/Projects/brindle # or from a local checkout
|
|
|
59
59
|
brindle drives Claude Code, so you need that too (`npm install -g @anthropic-ai/claude-code`).
|
|
60
60
|
|
|
61
61
|
`brindle --version` prints the installed version; the tmux status bar of every brindle
|
|
62
|
-
session shows it too (`brindle 0.3.
|
|
62
|
+
session shows it too (`brindle 0.3.3`). A session started before an upgrade keeps
|
|
63
63
|
running the old code, and shows the old number, until you restart it.
|
|
64
64
|
|
|
65
65
|
## Quick start
|
|
@@ -509,6 +509,7 @@ Autopilot, merge gates and cleanup:
|
|
|
509
509
|
| `merge_into` | none | branch that worker branches are cut from and merge into, whatever branch the supervisor is on |
|
|
510
510
|
| `auto_merge_default_branch` | `false` | let the pipeline merge into the repo's default branch (origin HEAD, else `main`/`master`) on its own; by default it sends a "needs you" message instead, and you run `merge_workspace` yourself (manual merges are never gated) |
|
|
511
511
|
| `permission_policy` | `"off"` | `"on"`: brindle answers Claude Code workers' permission prompts from its rules (see "Permission policy" below); off, the prompts behave as they always did |
|
|
512
|
+
| `agy_approvals` | `"prompt"` | `"brindle"`: with the policy on, Antigravity workers run without approval prompts and brindle's hook allows or denies every call (see "Antigravity" under "Permission policy") |
|
|
512
513
|
| `rules` | `[]` | standing rules for the supervisor, e.g. `["Fix review findings without asking", "Validate options before offering them"]`; added to every supervisor's brief. Rules in `~/.brindle/config.json`, the repo's config and `config.local.json` are all kept, so a team's rules and your own add up |
|
|
513
514
|
| `plan_first` | `false` | workers propose a plan (`submit_plan`) and wait for `approve_plan` before editing |
|
|
514
515
|
| `overlap` | `"block"` | a task whose `files` overlap a running task's is refused (`"warn"` starts it with a warning) |
|
|
@@ -572,6 +573,21 @@ keep theirs):
|
|
|
572
573
|
No tier prefers another provider for its own sake: all-Claude or all-Codex may
|
|
573
574
|
be what works best for you, and that's for the learner to find out.
|
|
574
575
|
|
|
576
|
+
Routing merges per tier in this order: built-in defaults, `~/.brindle/config.json`
|
|
577
|
+
(every repo), the repo's `.brindle/config.json` (shared with the team), then
|
|
578
|
+
`.brindle/config.local.json` (your override for that repo). Each tier you set
|
|
579
|
+
replaces that tier's list; tiers you leave out keep the list from the layer below.
|
|
580
|
+
For example, put this in `~/.brindle/config.json` to use Codex for light tasks
|
|
581
|
+
in every repo, or in a repo's `.brindle/config.local.json` to do so only there:
|
|
582
|
+
|
|
583
|
+
```json
|
|
584
|
+
{"routing": {"light": ["developer-codex", "developer"]}}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Run `brindle doctor` in the repo to see the effective list and source file for
|
|
588
|
+
each tier. Unknown profile names are skipped; doctor and the routing reply
|
|
589
|
+
report the missing name and the file that supplied it.
|
|
590
|
+
|
|
575
591
|
`developer-light` runs on Claude Haiku at low effort; `developer` on your Claude
|
|
576
592
|
Code default model; `developer-codex` on Codex; `developer-heavy` on Claude Fable
|
|
577
593
|
at high effort.
|
|
@@ -582,6 +598,53 @@ wins. When every candidate is out, the repo's `default_agent` runs. The reply sa
|
|
|
582
598
|
what was picked and why, e.g. `weight medium -> developer (Codex at 93%, skipped developer-codex)`.
|
|
583
599
|
An `agent_profile` you pass, or a milestone's `profile`, always wins over weight.
|
|
584
600
|
|
|
601
|
+
Provisioning and routing also check explicit models against supported read-only
|
|
602
|
+
catalogs, with the managed model, stored keys and the worker's filtered pane
|
|
603
|
+
environment. A model absent from a complete authoritative catalog is rejected
|
|
604
|
+
before creating a worker worktree or process. Partial catalogs, aliases,
|
|
605
|
+
discovery errors and Codex's bundled catalogs remain unverified; being listed
|
|
606
|
+
does not prove generation access, billing or quota. Catalog discovery is bounded
|
|
607
|
+
to five seconds for standalone checks; foreground routing/provisioning limits
|
|
608
|
+
discovery to one second, leaving room in the three-second launch budget for
|
|
609
|
+
provisioning and bounded helper cleanup. A timeout remains unverified and
|
|
610
|
+
launch proceeds with the real-task health follow-up. Catalogs are cached
|
|
611
|
+
briefly by environment and local account/config
|
|
612
|
+
revision where available. Routing and provisioning reuse equivalent catalog
|
|
613
|
+
context across worktrees, excluding launch bookkeeping while retaining project
|
|
614
|
+
settings, credentials and account selectors. CLI catalogs remain advisory;
|
|
615
|
+
unobservable external/keychain login changes may remain cached for 30 seconds.
|
|
616
|
+
Custom CLI binaries retain separate cache entries per working directory.
|
|
617
|
+
Claude, Bedrock, Vertex and Foundry have no catalog
|
|
618
|
+
probe here; no Claude CLI or synthetic generation request is used for these checks.
|
|
619
|
+
|
|
620
|
+
The real first worker task is sent once. A detached helper inspects its current
|
|
621
|
+
pane five seconds after delivery, so readiness delays do not use up that window.
|
|
622
|
+
Fresh interactive Antigravity chats without a task still receive their profile,
|
|
623
|
+
tool instructions and any autopilot context once after readiness; worker
|
|
624
|
+
instructions accompany the actual task in the same delivery.
|
|
625
|
+
For argv tasks, the timer starts at prompt submission or observed CLI readiness,
|
|
626
|
+
after trust/startup handling; readiness timeout does not establish delivery or
|
|
627
|
+
release queued work. Paused workers, replaced launches and reassigned panes are
|
|
628
|
+
excluded from the observation.
|
|
629
|
+
Explicit fresh authentication, access, model and capacity errors, or an early
|
|
630
|
+
exit, produce a safe supervisor message with a next step. A live process with
|
|
631
|
+
no clear result is recorded as pending for diagnostics, not verified model
|
|
632
|
+
access; it does not send a supervisor notification. Refusals use
|
|
633
|
+
the existing one-hour cooldown, scoped to the effective model/environment and
|
|
634
|
+
local login revision. Changing the account, model or credentials invalidates
|
|
635
|
+
that refusal; CLI/keychain account changes without an observable local revision
|
|
636
|
+
may require waiting for the cooldown or clearing `model_refusals.json`.
|
|
637
|
+
This is a single observation, not an entitlement test: unfamiliar error layouts,
|
|
638
|
+
later failures and slow requests can remain pending. It does not scan
|
|
639
|
+
historical transcripts, and excludes task text, previous pane lines and older
|
|
640
|
+
marked replies, fenced examples and ordinary assistant/tool explanations. A
|
|
641
|
+
Codex follow-up retains the complete submitted argv prompt (including profile
|
|
642
|
+
instructions) and distinguishes assistant/tool responses from the idle composer.
|
|
643
|
+
Quoted prompts and error-looking markers inside assistant/tool output remain
|
|
644
|
+
ambiguous and pending; markers from another provider do not establish failure.
|
|
645
|
+
A separate detached check covers headless and argv startup exits before task
|
|
646
|
+
delivery. Existing readiness and watch/cull handling continues afterward.
|
|
647
|
+
|
|
585
648
|
**Hosted learning (brindle Pro).** With a plan that includes it, brindle learns
|
|
586
649
|
which of your `learning_candidates` profiles suits which kind of task, and picks
|
|
587
650
|
one when `assign` gets no profile and no milestone names one (the reply says
|
|
@@ -680,6 +743,38 @@ Codex patches are checked file by file: allowed only if every file is. Codex
|
|
|
680
743
|
doesn't say which tool run followed which prompt, so brindle doesn't learn from
|
|
681
744
|
Codex approvals. To undo, delete that entry (or untrust it in Codex's `/hooks`).
|
|
682
745
|
|
|
746
|
+
Codex also uses the profile's `allowed_tools` shell entries: `Bash(just lint)`
|
|
747
|
+
allows that exact command, and `Bash(task test:*)` allows it with arguments.
|
|
748
|
+
The same simple-command restriction applies, and default, user, repo and
|
|
749
|
+
profile denies still win. Other `allowed_tools` entries aren't translated.
|
|
750
|
+
An unrecognized patch header prevents automatic approval without discarding
|
|
751
|
+
denies for files brindle can identify. Session/status bookkeeping failures
|
|
752
|
+
don't discard the hook's decision; failures to evaluate the policy leave
|
|
753
|
+
Codex's normal approval flow in place.
|
|
754
|
+
|
|
755
|
+
Scope and platform limits: this is an **approval-request hook**, not a gate
|
|
756
|
+
on every tool call. Codex commands already permitted by its sandbox or own
|
|
757
|
+
rules never reach it, so brindle cannot enforce denies on those calls. It
|
|
758
|
+
doesn't change Codex's sandbox or approval mode, and cannot make a `never`
|
|
759
|
+
approval mode interactive. Disabled hooks, managed-only hook policies, older
|
|
760
|
+
Codex versions without `PermissionRequest`, and nonlocal execution can prevent
|
|
761
|
+
the hook from running. Keep Codex's own restrictions for tools that must always
|
|
762
|
+
be blocked. See the [OpenAI hook protocol](https://learn.chatgpt.com/docs/hooks).
|
|
763
|
+
|
|
764
|
+
The integration targets local macOS/Linux Codex CLI processes (POSIX shell
|
|
765
|
+
quoting); native Windows hook commands aren't supported. The local app-server
|
|
766
|
+
protocol was checked on macOS with Codex CLI **0.162.1**: newline-delimited
|
|
767
|
+
`initialize`, `initialized`, and `hooks/list` returned the session-flags key
|
|
768
|
+
above, `eventName: "permissionRequest"`, `source: "sessionFlags"`,
|
|
769
|
+
`currentHash`, `enabled: true`, and `trustStatus: "trusted"` for the installed
|
|
770
|
+
brindle hook. This read-only probe made no model calls or trust edits; hook
|
|
771
|
+
dispatch/allow/deny behavior is covered by the permission tests. Linux runtime
|
|
772
|
+
and native Windows behavior were not exercised by that probe.
|
|
773
|
+
`codex features list` also reported `hooks stable true` without a user
|
|
774
|
+
`features.hooks` setting, both on 0.162.1 and the bundled 0.158.0-alpha.2.1.
|
|
775
|
+
A session override of `features.hooks=false` reported false. No feature-enable
|
|
776
|
+
flag is needed on these versions, and brindle leaves explicit disablement alone.
|
|
777
|
+
|
|
683
778
|
**Antigravity.** agy's hook can deny but its "allow" is ignored (an agy bug),
|
|
684
779
|
and it has no "no opinion" answer. So the hook denies what the policy denies,
|
|
685
780
|
answers "allow" for a file inside the workspace (which agy reads and writes
|
|
@@ -696,6 +791,21 @@ does it by hand. To undo, turn `permission_policy` off and run `sync-agy`: brind
|
|
|
696
791
|
removes exactly its own entries. brindle doesn't learn from agy approvals (its
|
|
697
792
|
hook runs for every tool call, so a tool running doesn't mean you approved it).
|
|
698
793
|
|
|
794
|
+
With `"agy_approvals": "brindle"` (and the policy on), brindle's hook is the
|
|
795
|
+
only gate instead: agy workers start with `--dangerously-skip-permissions`,
|
|
796
|
+
under which agy still honors a hook's deny, and the hook runs on every tool,
|
|
797
|
+
subagents' calls included. It allows what a rule allows (a repo's checks
|
|
798
|
+
included), the shell commands in the profile's `allowed_tools` (what a Claude
|
|
799
|
+
Code worker on it runs without asking), files inside the workspace given as one
|
|
800
|
+
absolute path (writes under `.agents/`, `.git/` and
|
|
801
|
+
`.brindle/` only by a rule, since those hold the hook, git's hooks and the
|
|
802
|
+
repo's checks), brindle's own tools and agy's tools that act only on the
|
|
803
|
+
conversation, and denies everything else, telling the agent to
|
|
804
|
+
ask its supervisor; you allow it with `brindle permissions allow`. Any failure
|
|
805
|
+
in the hook is a deny, and a tool brindle doesn't know is denied. Nobody can
|
|
806
|
+
approve a prompt in the agent's pane in this mode. The default, `"prompt"`,
|
|
807
|
+
leaves agy asking as described above.
|
|
808
|
+
|
|
699
809
|
## brindle Pro and Team
|
|
700
810
|
|
|
701
811
|
brindle is complete on its own. brindle Pro adds hosted learning (which profile
|