brindle 0.0.2__tar.gz → 0.0.4__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.0.2 → brindle-0.0.4}/PKG-INFO +109 -134
- {brindle-0.0.2 → brindle-0.0.4}/README.md +108 -133
- {brindle-0.0.2 → brindle-0.0.4}/pyproject.toml +1 -1
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/agents.py +81 -24
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/autopilot.py +67 -25
- brindle-0.0.4/src/brindle/ci_adapters.py +662 -0
- brindle-0.0.4/src/brindle/ci_client.py +1371 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/cli.py +139 -77
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/config.py +1 -1
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/cull.py +34 -12
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/db.py +66 -11
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/doctor.py +73 -13
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/mcp_server.py +162 -41
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/client.py +25 -1
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/account.py +3 -2
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/auth.py +24 -4
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/license.py +47 -31
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/providers.py +182 -32
- brindle-0.0.4/src/brindle/repo_cmds.py +74 -0
- brindle-0.0.4/src/brindle/repos.py +245 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/sessions.py +35 -4
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/tasks.py +45 -11
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/tmux.py +161 -36
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/view.py +24 -1
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/watch.py +34 -13
- brindle-0.0.2/src/brindle/ci.py +0 -948
- {brindle-0.0.2 → brindle-0.0.4}/.gitignore +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/LICENSE +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/SCHEDULE-A +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/__main__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/account.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/airgap.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/antigravity.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/developer-codex.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/developer-heavy.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/developer-local.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/developer.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/reviewer-codex.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/reviewer-local.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/reviewer.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/subagent.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/builtin_agents/supervisor.md +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/codemap.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/codex_hook.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/demo.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/detect.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/events.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/gates.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/git.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/history.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/inbox.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/learning.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/legacy.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/loop.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/permissions.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/runner.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/serve.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/native/tools.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/permissions.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pipeline.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/plugins.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/policy.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pool.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/_files.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/audit_chain.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/credentials.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/features.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/keys.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/learning.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/loopback.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/orgkey.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/settings_sync.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/team_events.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/pro/team_policy.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/procs.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/profiles.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/quota.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/savings.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/scratch.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/services.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/sidebar_follow.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/status_cache.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/usage.py +0 -0
- {brindle-0.0.2 → brindle-0.0.4}/src/brindle/workspaces.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brindle
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
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
|
|
@@ -45,9 +45,9 @@ curl -fsSL pawdelta.com/brindle/install | sh
|
|
|
45
45
|
brindle demo # watch it finish a practice repo in a few minutes
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-

|
|
48
|
+

|
|
49
49
|
|
|
50
|
-
*`brindle demo`, recorded on brindle 0.
|
|
50
|
+
*`brindle demo`, recorded on brindle 0.0.2 (sped up 4×): two workers in parallel, each branch reviewed and merged, both milestones verified by their check commands.*
|
|
51
51
|
|
|
52
52
|
- **Done means a command passed.** A goal is split into milestones, each with a
|
|
53
53
|
check command that brindle runs itself. A milestone is verified when its check exits
|
|
@@ -89,13 +89,9 @@ 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.
|
|
92
|
+
session shows it too (`brindle 0.0.4`). 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
|
-
### Upgrading from copse
|
|
96
|
-
|
|
97
|
-
brindle was called copse until 0.0.1, and it doesn't read anything copse saved. Install `brindle`, then move `~/.copse` to `~/.brindle` and each repo's `.copse/` to `.brindle/`. Until you do, saved permission rules, policy and config there don't apply. `brindle doctor` lists every leftover it finds, including old `copse` entries in `.agents/hooks.json` and `mcp_config.json` to remove.
|
|
98
|
-
|
|
99
95
|
## Quick start
|
|
100
96
|
|
|
101
97
|
```sh
|
|
@@ -345,6 +341,7 @@ your own status line prints, so what you see doesn't change.
|
|
|
345
341
|
| `brindle delegation [conservative\|balanced\|fast]` | how readily the supervisor delegates: fewest tokens, the default, or quickest |
|
|
346
342
|
| `brindle transfer [REPO] [--from SESSION] [-b BRANCH]` | move a scratch session's work into a real repo |
|
|
347
343
|
| `brindle ls [--all]` | workspaces and agents |
|
|
344
|
+
| `brindle repo add PATH [--name ALIAS] / rm ALIAS / ls` | attach other local repos to the current session so workers can go there (brindle Pro; see "Several repos in one session") |
|
|
348
345
|
| `brindle history [--limit N] [--kind K] [--all]` | durable log of worker results, reviews, merges and milestone checks |
|
|
349
346
|
| `brindle history --share [--session ID]` | a few lines about this session to paste into Slack or a post: goal, milestones verified, workers, merges, reviews (and how many by a different model), parallel speedup, tokens |
|
|
350
347
|
| `brindle permissions list / check / suggestions / accept / allow / deny / forget / reset` | the rules brindle answers workers' permission requests with, and what it suggests from your approvals (see "Permission policy") |
|
|
@@ -380,6 +377,7 @@ knowing them helps when you tell the supervisor how to work.
|
|
|
380
377
|
| `send_message` | any agent | message another agent; delivered when it's idle |
|
|
381
378
|
| `read_messages` | supervisor | read the messages agents and brindle sent you and mark them read; with `message_delivery` `"pull"` (the default) you get a one-line "N new messages" notice instead of each message |
|
|
382
379
|
| `list_agents` / `list_tasks` / `list_agent_profiles` | supervisor | who's running, what's queued, which profiles exist |
|
|
380
|
+
| `list_repos` | supervisor | the repos attached to the session (brindle Pro); `repo=<alias>` on `assign`/`handoff` puts a worker there |
|
|
383
381
|
| `cancel_task` | supervisor | cancel a queued task (and its dependents) to re-plan |
|
|
384
382
|
| `workspace_diff` | supervisor | a worker branch's changes against its base |
|
|
385
383
|
| `request_review` / `submit_review` | supervisor / reviewer | start a reviewer on a branch / record its verdict |
|
|
@@ -484,7 +482,7 @@ Autopilot, merge gates and cleanup:
|
|
|
484
482
|
| `sidebar` | `"left"` | where the dashboard sits in each window: `"left"` of the chat, or `"bottom"` (full-width rows under it) |
|
|
485
483
|
| `delegation` | `"balanced"` | how readily the supervisor hands work to workers. `"conservative"` does most work in its own chat (fewest tokens), `"fast"` splits any multi-part request across parallel workers straight away (quickest, most tokens). `brindle delegation fast` saves it for every repo and session (in `~/.brindle/config.json`; `--repo` for this repo only) and tells a running supervisor |
|
|
486
484
|
| `delete_merged_branches` | `true` | removing a worktree (after a merge, `brindle rm`, `brindle prune`, session cleanup) also deletes its branch once every commit is in its base, so finished branches don't pile up. An unmerged branch is always kept; `false` keeps them all. If GitHub keeps merged PR branches, the first `brindle pr` in a repo offers to turn on its automatic deletion with your `gh` login (repo admins only) |
|
|
487
|
-
| `pr_footer` | `true` | `brindle pr`
|
|
485
|
+
| `pr_footer` | `true` | `brindle pr` ends the PR description with one line: "🌲 Built in parallel and verified with brindle" (a link). `false` leaves it out. Never added to commit messages |
|
|
488
486
|
| `message_delivery` | `"pull"` | how agent and brindle messages reach an interactive supervisor: `"pull"` keeps them unread and delivers one notice ("brindle (16:25:03): 2 new messages (from 9f742c5c, pipeline). Call read_messages."; the time keeps Claude Code from dropping a repeat; the sidebar shows an unread count), `"push"` delivers each message's text. Messages you send (`brindle send`, typing) and messages to workers are always pushed |
|
|
489
487
|
| `learning` | `"auto"` | hosted learning (brindle Pro, via the API; see below): `"auto"` uses it when your plan includes it and nothing otherwise; `"cloud"`; `"off"`. Any other value means off |
|
|
490
488
|
| `learning_candidates` | `[]` | the profile names the hosted learner may pick from |
|
|
@@ -672,6 +670,7 @@ how to use them, and the next step to get the rest:
|
|
|
672
670
|
|---|---|---|
|
|
673
671
|
| hosted learning | Pro | on by itself; `brindle learning` |
|
|
674
672
|
| per-worktree services | Pro | `"services"` in `.brindle/config.json` |
|
|
673
|
+
| several repos in one session | Pro | `brindle repo add <path>` |
|
|
675
674
|
| org policies + audit feed | Team | `brindle account org policy` |
|
|
676
675
|
| Brindle-CI | Team | `brindle ci init` |
|
|
677
676
|
| audit log, air-gap | Enterprise | `brindle audit verify`, `"airgap": true` |
|
|
@@ -689,6 +688,21 @@ brindle account org member policy-role <member> <role|none> # give a member a
|
|
|
689
688
|
brindle account org company [link <org_id> | unlink] # link orgs you own into one company; learning is pooled only within it
|
|
690
689
|
```
|
|
691
690
|
|
|
691
|
+
### Several repos in one session (brindle Pro)
|
|
692
|
+
|
|
693
|
+
A session can work across several repos. Attach another local repo you own
|
|
694
|
+
to the running session and the supervisor can put workers there: each gets a
|
|
695
|
+
worktree in that repo, that repo's own checks and review, and merges into that
|
|
696
|
+
repo's branch. A task may depend on one in another repo, a milestone check can
|
|
697
|
+
run in another repo (`check@<alias>: <command>` in `goals.md`, or `repo` in
|
|
698
|
+
`set_goal`), and the sidebar and `brindle ls` group workers by repo.
|
|
699
|
+
|
|
700
|
+
```sh
|
|
701
|
+
brindle repo add ../pawdelta-web --name web # attach a repo to the current session (alias: web)
|
|
702
|
+
brindle repo ls # the repos attached to this session
|
|
703
|
+
brindle repo rm web # detach it (its worktrees and branches stay)
|
|
704
|
+
```
|
|
705
|
+
|
|
692
706
|
Setting up a team takes no sign-up form:
|
|
693
707
|
|
|
694
708
|
```sh
|
|
@@ -792,129 +806,61 @@ brindle audit pubkey # this install's public key (
|
|
|
792
806
|
one altered in place (hash or signature), one removed, inserted or reordered
|
|
793
807
|
(seq and prev_hash), or a truncated tail. Verifying and exporting never need
|
|
794
808
|
the entitlement, so a log keeps its value after a plan lapses.
|
|
795
|
-
### Brindle-CI: issues into pull requests
|
|
796
|
-
|
|
797
|
-
brindle Team can run brindle with nobody at a terminal. `brindle ci run` cuts a
|
|
798
|
-
`brindle/ci-<issue or slug>` branch, starts a supervisor with autopilot on in a
|
|
799
|
-
detached tmux session, gives it the goal, and waits until every milestone's
|
|
800
|
-
check passes. Then it pushes the branch and opens the pull request with `gh`
|
|
801
|
-
(the body lists the goal, the milestones and their checks, and `Closes #N`
|
|
802
|
-
for an issue), prints the PR URL and exits 0; with `--bundle` it writes the
|
|
803
|
-
branch to a file instead, for `brindle ci publish` (see below). It exits 1, with what happened,
|
|
804
|
-
when the supervisor asks for a decision (`need_user`: the question is the
|
|
805
|
-
reason), stalls, or runs out of time. The session and its workers are always
|
|
806
|
-
stopped at the end, and a JSON summary goes to `$GITHUB_STEP_SUMMARY` when
|
|
807
|
-
that is set.
|
|
808
|
-
|
|
809
|
-
```sh
|
|
810
|
-
brindle ci run --issue 42 # the goal is the issue's title and body
|
|
811
|
-
brindle ci run --goal "Add a /health endpoint" # or typed; a goals.md-shaped text brings its milestones
|
|
812
|
-
brindle ci run --goal-file .brindle/goals.md --timeout 90 --max-workers 2 --base develop --no-pr
|
|
813
|
-
brindle ci init --label brindle # the GitHub Actions workflow (see below)
|
|
814
|
-
|
|
815
|
-
# The same run in three steps, so no secret worth stealing is near the agents:
|
|
816
|
-
brindle ci entitle --out ent.jwt # uses BRINDLE_PRO_TOKEN, then exits
|
|
817
|
-
brindle ci run --issue 42 --entitlement ent.jwt --bundle out/brindle.bundle # no CI token, no push token
|
|
818
|
-
brindle ci publish out/brindle.bundle --repo acme/api # elsewhere: pushes and opens the PR
|
|
819
|
-
```
|
|
820
809
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
`
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
default). It has three jobs:
|
|
868
|
-
|
|
869
|
-
- `entitle` (no permissions) runs `brindle ci entitle` with `BRINDLE_PRO_TOKEN`
|
|
870
|
-
on a machine that checks out and runs nothing from the repo. It hands the
|
|
871
|
-
short-lived entitlement (three hours) to the next job as an artifact kept
|
|
872
|
-
one day, so the CI token is never on the agents' machine.
|
|
873
|
-
- `run` (permissions: `contents: read`, `issues: read`) checks the repo out
|
|
874
|
-
without keeping credentials, installs tmux, brindle (pinned to the version
|
|
875
|
-
that wrote the workflow) and Claude Code, then runs `brindle ci run --issue
|
|
876
|
-
<number> --entitlement … --bundle …` with only `ANTHROPIC_API_KEY` and a
|
|
877
|
-
read-only `GH_TOKEN`. brindle deletes the entitlement file before any agent
|
|
878
|
-
starts. The job uploads the bundle as an artifact.
|
|
879
|
-
- `publish` (permissions:
|
|
880
|
-
`contents: write`, `pull-requests: write`) starts on a fresh machine, checks
|
|
881
|
-
nothing out, downloads the artifact and runs `brindle ci publish`, targeting
|
|
882
|
-
the repository's default branch.
|
|
883
|
-
|
|
884
|
-
`brindle ci init` won't
|
|
885
|
-
overwrite an existing file without `--force`. The workflow needs two secrets,
|
|
886
|
-
`BRINDLE_PRO_TOKEN` (an org CI token, below) and `ANTHROPIC_API_KEY`, and the
|
|
887
|
-
repo's Actions settings must allow GitHub Actions to create pull requests.
|
|
888
|
-
The model API key is the one secret agents must have; give it a spending
|
|
889
|
-
limit.
|
|
890
|
-
|
|
891
|
-
An org admin creates the CI token; it is shown once, so store it straight away:
|
|
892
|
-
|
|
893
|
-
```sh
|
|
894
|
-
brindle account org ci-token create "acme/api actions" --org org_... # prints cpc_... once
|
|
895
|
-
gh secret set BRINDLE_PRO_TOKEN # paste it
|
|
896
|
-
brindle account org ci-token list --org org_... # names, status, last used; never the secret
|
|
897
|
-
brindle account org ci-token revoke ct_... --org org_... # CI stops at its next run
|
|
810
|
+
### Brindle-CI
|
|
811
|
+
|
|
812
|
+
Brindle-CI (brindle Team) brings brindle into your CI: it fixes broken builds,
|
|
813
|
+
turns issues into pull requests whose checks it has verified, and reviews pull
|
|
814
|
+
requests with evidence. It runs on your own CI with your own model keys; the
|
|
815
|
+
hosted control plane decides what each run does and what it reports. The
|
|
816
|
+
workflows call these commands:
|
|
817
|
+
|
|
818
|
+
- `brindle ci init`: set a repository up in one go (the GitHub App, the secrets,
|
|
819
|
+
the workflows as a pull request, then a doctor check). Run it inside a
|
|
820
|
+
checkout of the repository. For Claude it asks whether to use an API key
|
|
821
|
+
(the `ANTHROPIC_API_KEY` secret) or Anthropic
|
|
822
|
+
[workload identity federation](https://platform.claude.com/docs/en/manage-claude/wif-reference)
|
|
823
|
+
(`--credential key|federation` answers without asking).
|
|
824
|
+
- `brindle ci doctor`: which provider CLIs and credential names a runner has, and
|
|
825
|
+
which providers CI may use on this repository.
|
|
826
|
+
- `brindle ci start`: start a run for an issue, a goal text or a dispatched run,
|
|
827
|
+
or a validation of a pull request.
|
|
828
|
+
- `brindle ci run`: run what was started: the supervisor and the result upload,
|
|
829
|
+
or the pull request's checks and reviews and the evidence upload.
|
|
830
|
+
- `brindle ci report`: tell the service how the workflow's jobs ended.
|
|
831
|
+
|
|
832
|
+
Credential names are reported, never values. On a repository owned by a GitHub
|
|
833
|
+
organization, a provider signed in only with a personal subscription is not used.
|
|
834
|
+
|
|
835
|
+
An Anthropic API key is either a workspace key (scoped to one workspace) or an
|
|
836
|
+
organization-level key (not scoped to a workspace). An organization-level key
|
|
837
|
+
needs the workspace in every request, so after the key `brindle ci init` asks for
|
|
838
|
+
its workspace ID (`wrkspc_...`; leave it blank for a workspace key, or pass
|
|
839
|
+
`--workspace-id`, default `$ANTHROPIC_WORKSPACE_ID`) and stores it as the Actions
|
|
840
|
+
variable `ANTHROPIC_WORKSPACE_ID`. The workflow then sets
|
|
841
|
+
`ANTHROPIC_CUSTOM_HEADERS="anthropic-workspace-id: <id>"`, which reaches every
|
|
842
|
+
Claude Code process the run starts.
|
|
843
|
+
|
|
844
|
+
With identity federation the repository stores no Anthropic key: the workflow
|
|
845
|
+
exchanges GitHub's OIDC token once for a short-lived Anthropic token, as a
|
|
846
|
+
Claude Console service account (billed as API, so it is allowed on
|
|
847
|
+
organization repositories), and gives the job `ANTHROPIC_AUTH_TOKEN`. `brindle
|
|
848
|
+
ci init` stores the rule, organization, service account and optional workspace
|
|
849
|
+
IDs as the Actions variables `ANTHROPIC_FEDERATION_RULE_ID`,
|
|
850
|
+
`ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` and
|
|
851
|
+
`ANTHROPIC_WORKSPACE_ID`. Create the federation rule in the Claude Console with
|
|
852
|
+
subject prefix `repo:<owner>/<name>:*`, the condition
|
|
853
|
+
|
|
854
|
+
```text
|
|
855
|
+
claims.repository == "<owner>/<name>" && claims.workflow_ref.startsWith("<owner>/<name>/.github/workflows/brindle-ci-")
|
|
898
856
|
```
|
|
899
857
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
Two things to know before you add the label to your repo:
|
|
908
|
-
|
|
909
|
-
- **Who can apply the label.** The issue body steers an unattended agent
|
|
910
|
-
whose work becomes a pull request on a `brindle/ci-` branch. Only people you
|
|
911
|
-
trust with write access should be able to apply the trigger label; on a
|
|
912
|
-
public repo, anyone who can write the issue text is choosing what the agent
|
|
913
|
-
is told to do. Review the pull request like any other before merging it.
|
|
914
|
-
- **CI on the pull request.** A PR opened with the workflow's own
|
|
915
|
-
`GITHUB_TOKEN` doesn't trigger the repo's other workflows. If you want your
|
|
916
|
-
checks to run on brindle's PRs, set `GH_TOKEN` in the `publish` job to a
|
|
917
|
-
GitHub App installation token or a personal access token instead.
|
|
858
|
+
audience `https://api.anthropic.com`, and a token lifetime of at least 7200
|
|
859
|
+
seconds. The condition lets only brindle's workflows mint tokens. On pull
|
|
860
|
+
requests the pull request's own copy of the validate workflow runs, so give
|
|
861
|
+
write access only to people you trust (forks never get a token). Leave the `ANTHROPIC_API_KEY` secret
|
|
862
|
+
unset: a key takes precedence (brindle drops an empty one before Claude Code
|
|
863
|
+
starts).
|
|
918
864
|
|
|
919
865
|
**Closing and cleaning up.** Press `x` on an agent in the sidebar (twice for one
|
|
920
866
|
that's still running) or run `brindle close <id>` to stop it and hide it. Stopping means
|
|
@@ -1056,14 +1002,34 @@ change files under a directory without prompts.
|
|
|
1056
1002
|
brindle only offers a profile whose CLI is installed and signed in. A profile on a
|
|
1057
1003
|
CLI that isn't signed in is left out of the supervisor's profile list and of
|
|
1058
1004
|
routing by weight, and naming it directly stops with how to sign in
|
|
1059
|
-
(`claude auth login`, `codex login`) instead of opening the CLI's
|
|
1060
|
-
`brindle doctor` shows each CLI's
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1005
|
+
(`claude auth login`, `codex login`, running `agy`) instead of opening the CLI's
|
|
1006
|
+
login screen. `brindle doctor` shows, for each installed CLI, how it's signed in
|
|
1007
|
+
and whether a quota limit is in effect. Sign-in is its own login, an environment
|
|
1008
|
+
key (by name, never its value) set in your shell or in a profile's
|
|
1009
|
+
`env.NAME: value` lines, signed out, or unknown when the status check gives no
|
|
1010
|
+
answer. Keys set in the environment (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
|
|
1011
|
+
`GEMINI_API_KEY` and the like) count as signed in; see the table below for what
|
|
1012
|
+
each CLI takes. A worker that no hook reports on (Codex)
|
|
1064
1013
|
and that shows nothing new for 10 minutes without reporting, for example because
|
|
1065
1014
|
it's signed in without a plan that includes it, is reported to its supervisor.
|
|
1066
1015
|
|
|
1016
|
+
#### Key login
|
|
1017
|
+
|
|
1018
|
+
| Provider | Key login (environment variables) |
|
|
1019
|
+
|---|---|
|
|
1020
|
+
| `claude` | yes: `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, or Bedrock/Vertex/Foundry (`CLAUDE_CODE_USE_BEDROCK`, `CLAUDE_CODE_USE_VERTEX`, `CLAUDE_CODE_USE_FOUNDRY`) |
|
|
1021
|
+
| `codex` | yes: `OPENAI_API_KEY`, `CODEX_API_KEY` |
|
|
1022
|
+
| `antigravity` | `GEMINI_API_KEY`, only with `"modelProvider": "gemini"` in `agy`'s `settings.json` (see [Google Antigravity](#google-antigravity)); otherwise `agy`'s own browser sign-in |
|
|
1023
|
+
|
|
1024
|
+
Workers that run unattended should use key login where the CLI supports it.
|
|
1025
|
+
A personal login is one interactive session with one quota shared by every
|
|
1026
|
+
worker: when it expires or its quota runs out, every worker on it stalls until
|
|
1027
|
+
someone signs in again in a browser. A key gives workers their own limits and
|
|
1028
|
+
needs no browser step. Put the key in your environment, or in a profile's
|
|
1029
|
+
`env.NAME: value` lines in `~/.brindle/agents` (never in the repo), and
|
|
1030
|
+
`brindle doctor` names the variable each CLI gets, from your shell or from
|
|
1031
|
+
which profiles.
|
|
1032
|
+
|
|
1067
1033
|
### Cheap workers
|
|
1068
1034
|
|
|
1069
1035
|
By default a Claude Code worker loads everything your own `claude` does: your
|
|
@@ -1298,6 +1264,15 @@ curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
|
1298
1264
|
agy # sign in with your Google account, then quit
|
|
1299
1265
|
```
|
|
1300
1266
|
|
|
1267
|
+
To run unattended workers without a browser login, `agy` (1.1.13 or newer) can use
|
|
1268
|
+
a Gemini API key instead: put `"modelProvider": "gemini"` in
|
|
1269
|
+
`~/.gemini/antigravity-cli/settings.json` and set `GEMINI_API_KEY`, in your
|
|
1270
|
+
environment or in a profile's `env.GEMINI_API_KEY: ...` line (keep the key out of
|
|
1271
|
+
the repo). The key alone does nothing: without `modelProvider`, `agy` still asks
|
|
1272
|
+
you to sign in. `agy` takes no other key or token from the environment; its
|
|
1273
|
+
Google Cloud, Workforce Identity and Application Default Credentials sign-ins are
|
|
1274
|
+
chosen on its sign-in screen.
|
|
1275
|
+
|
|
1301
1276
|
Then run the whole session on it with `brindle --provider antigravity`, or mix models:
|
|
1302
1277
|
give a profile `provider: antigravity` (for example a `gemini-reviewer` for a second
|
|
1303
1278
|
model's review) and the supervisor can hand it tasks.
|