brindle 0.0.2__tar.gz → 0.0.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.0.2 → brindle-0.0.3}/PKG-INFO +75 -134
- {brindle-0.0.2 → brindle-0.0.3}/README.md +74 -133
- {brindle-0.0.2 → brindle-0.0.3}/pyproject.toml +1 -1
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/agents.py +81 -24
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/autopilot.py +67 -25
- brindle-0.0.3/src/brindle/ci_adapters.py +533 -0
- brindle-0.0.3/src/brindle/ci_client.py +1111 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/cli.py +136 -77
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/config.py +1 -1
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/cull.py +34 -12
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/db.py +66 -11
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/doctor.py +73 -13
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/mcp_server.py +162 -41
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/client.py +25 -1
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/account.py +3 -2
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/auth.py +24 -4
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/license.py +47 -31
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/providers.py +64 -19
- brindle-0.0.3/src/brindle/repo_cmds.py +74 -0
- brindle-0.0.3/src/brindle/repos.py +245 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/sessions.py +35 -4
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/tasks.py +45 -11
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/tmux.py +161 -36
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/view.py +24 -1
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/watch.py +34 -13
- brindle-0.0.2/src/brindle/ci.py +0 -948
- {brindle-0.0.2 → brindle-0.0.3}/.gitignore +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/LICENSE +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/SCHEDULE-A +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/__main__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/account.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/airgap.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/antigravity.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/developer-codex.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/developer-heavy.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/developer-local.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/developer.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/reviewer-codex.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/reviewer-local.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/reviewer.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/subagent.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/builtin_agents/supervisor.md +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/codemap.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/codex_hook.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/demo.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/detect.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/events.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/gates.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/git.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/history.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/inbox.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/learning.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/legacy.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/loop.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/permissions.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/runner.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/serve.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/native/tools.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/permissions.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pipeline.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/plugins.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/policy.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pool.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/__init__.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/_files.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/audit_chain.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/credentials.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/features.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/keys.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/learning.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/loopback.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/orgkey.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/settings_sync.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/team_events.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/pro/team_policy.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/procs.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/profiles.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/quota.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/savings.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/scratch.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/services.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/sidebar_follow.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/status_cache.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/src/brindle/usage.py +0 -0
- {brindle-0.0.2 → brindle-0.0.3}/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.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
|
|
@@ -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.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
|
-
### 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,8 +670,9 @@ 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
|
-
| Brindle-CI | Team |
|
|
675
|
+
| Brindle-CI | Team | back in a later release |
|
|
677
676
|
| audit log, air-gap | Enterprise | `brindle audit verify`, `"airgap": true` |
|
|
678
677
|
|
|
679
678
|
```sh
|
|
@@ -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,27 @@ 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
|
|
|
809
|
-
|
|
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
|
-
```
|
|
810
|
+
### Brindle-CI
|
|
820
811
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
**Who is trusted with what.** Agents run your repo's code: its tests, its
|
|
827
|
-
scripts, and whatever an issue talks them into. They run as the same user as
|
|
828
|
-
brindle, so treat everything on that machine as theirs to read: environment
|
|
829
|
-
variables, files, git and `gh` settings. brindle does take its tokens out of the
|
|
830
|
-
environment before agents start and pushes from a clean copy of the commits,
|
|
831
|
-
but that only makes theft harder. What actually protects a secret is that it
|
|
832
|
-
isn't on the machine while agents run. So the work can be split:
|
|
833
|
-
|
|
834
|
-
1. `brindle ci entitle --out FILE` exchanges `BRINDLE_PRO_TOKEN` for the signed,
|
|
835
|
-
short-lived entitlement and writes it to a file (mode 0600). Run it on a
|
|
836
|
-
different machine from the agents (the workflow gives it its own job):
|
|
837
|
-
on hosted runners agents have sudo, and the runner holds every secret of
|
|
838
|
-
the job they run in. `brindle ci run` reads the file and deletes it before
|
|
839
|
-
any agent starts.
|
|
840
|
-
2. `brindle ci run --entitlement FILE --bundle PATH` does the work with no CI
|
|
841
|
-
token and no token that can write to GitHub (`--issue` needs one that can
|
|
842
|
-
read). When the goal is verified it writes the new commits to PATH as a git
|
|
843
|
-
bundle, and `PATH.json` with the branch, base, title and body of the pull
|
|
844
|
-
request. `--bundle` implies `--no-pr`: nothing is pushed.
|
|
845
|
-
3. `brindle ci publish PATH [--repo owner/name]` runs where no agent ever ran,
|
|
846
|
-
with the token that can push. It verifies the bundle, fetches its one
|
|
847
|
-
`brindle/ci-…` branch into a fresh bare repo, pushes that branch to
|
|
848
|
-
`https://github.com/<repo>` (default: `$GITHUB_REPOSITORY`) and opens the
|
|
849
|
-
pull request with `gh`. It never checks out or runs repo code, hooks or
|
|
850
|
-
agents, and it refuses a bundle whose branch isn't a `brindle/ci-` branch, so
|
|
851
|
-
a run can't publish over `main`. The pull request targets `--base`, else
|
|
852
|
-
the repository's default branch; the bundle doesn't get to choose. A
|
|
853
|
-
hostile run can still add commits to an existing `brindle/ci-` branch.
|
|
854
|
-
|
|
855
|
-
The workflow `brindle ci init` writes pins brindle to the version that wrote it,
|
|
856
|
-
since the publishing job holds a write token. The short-lived entitlement
|
|
857
|
-
passes between jobs as an artifact kept one day. A CI entitlement expires
|
|
858
|
-
three hours after it's issued, so anyone who can download the repo's
|
|
859
|
-
artifacts could use it for that long at most.
|
|
860
|
-
|
|
861
|
-
`brindle ci run` without `--bundle` still pushes and opens the pull request
|
|
862
|
-
itself. Use that only where you trust the repo's code and everyone who can
|
|
863
|
-
steer the agents.
|
|
864
|
-
|
|
865
|
-
`brindle ci init` writes `.github/workflows/brindle.yml`, which runs on
|
|
866
|
-
`workflow_dispatch` and whenever an issue gets the label (`brindle` by
|
|
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:
|
|
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:
|
|
892
817
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
brindle
|
|
898
|
-
|
|
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).
|
|
820
|
+
- `brindle ci doctor`: which provider CLIs and credential names a runner has, and
|
|
821
|
+
which providers CI may use on this repository.
|
|
822
|
+
- `brindle ci start`: start a run for an issue, a goal text or a dispatched run,
|
|
823
|
+
or a validation of a pull request.
|
|
824
|
+
- `brindle ci run`: run what was started: the supervisor and the result upload,
|
|
825
|
+
or the pull request's checks and reviews and the evidence upload.
|
|
826
|
+
- `brindle ci report`: tell the service how the workflow's jobs ended.
|
|
899
827
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
memory and writes nothing to disk; `brindle ci entitle` writes only the signed
|
|
903
|
-
entitlement, which expires soon, never the token. The token doesn't rotate, so one secret
|
|
904
|
-
keeps working until it is revoked or the org's plan no longer includes CI. A
|
|
905
|
-
refresh token from `brindle account login` won't do: it rotates on use.
|
|
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.
|
|
828
|
+
Credential names are reported, never values. On a repository owned by a GitHub
|
|
829
|
+
organization, a provider signed in only with a personal subscription is not used.
|
|
918
830
|
|
|
919
831
|
**Closing and cleaning up.** Press `x` on an agent in the sidebar (twice for one
|
|
920
832
|
that's still running) or run `brindle close <id>` to stop it and hide it. Stopping means
|
|
@@ -1056,14 +968,34 @@ change files under a directory without prompts.
|
|
|
1056
968
|
brindle only offers a profile whose CLI is installed and signed in. A profile on a
|
|
1057
969
|
CLI that isn't signed in is left out of the supervisor's profile list and of
|
|
1058
970
|
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
|
-
|
|
971
|
+
(`claude auth login`, `codex login`, running `agy`) instead of opening the CLI's
|
|
972
|
+
login screen. `brindle doctor` shows, for each installed CLI, how it's signed in
|
|
973
|
+
and whether a quota limit is in effect. Sign-in is its own login, an environment
|
|
974
|
+
key (by name, never its value) set in your shell or in a profile's
|
|
975
|
+
`env.NAME: value` lines, signed out, or unknown when the status check gives no
|
|
976
|
+
answer. Keys set in the environment (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
|
|
977
|
+
`GEMINI_API_KEY` and the like) count as signed in; see the table below for what
|
|
978
|
+
each CLI takes. A worker that no hook reports on (Codex)
|
|
1064
979
|
and that shows nothing new for 10 minutes without reporting, for example because
|
|
1065
980
|
it's signed in without a plan that includes it, is reported to its supervisor.
|
|
1066
981
|
|
|
982
|
+
#### Key login
|
|
983
|
+
|
|
984
|
+
| Provider | Key login (environment variables) |
|
|
985
|
+
|---|---|
|
|
986
|
+
| `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`) |
|
|
987
|
+
| `codex` | yes: `OPENAI_API_KEY`, `CODEX_API_KEY` |
|
|
988
|
+
| `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 |
|
|
989
|
+
|
|
990
|
+
Workers that run unattended should use key login where the CLI supports it.
|
|
991
|
+
A personal login is one interactive session with one quota shared by every
|
|
992
|
+
worker: when it expires or its quota runs out, every worker on it stalls until
|
|
993
|
+
someone signs in again in a browser. A key gives workers their own limits and
|
|
994
|
+
needs no browser step. Put the key in your environment, or in a profile's
|
|
995
|
+
`env.NAME: value` lines in `~/.brindle/agents` (never in the repo), and
|
|
996
|
+
`brindle doctor` names the variable each CLI gets, from your shell or from
|
|
997
|
+
which profiles.
|
|
998
|
+
|
|
1067
999
|
### Cheap workers
|
|
1068
1000
|
|
|
1069
1001
|
By default a Claude Code worker loads everything your own `claude` does: your
|
|
@@ -1298,6 +1230,15 @@ curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
|
1298
1230
|
agy # sign in with your Google account, then quit
|
|
1299
1231
|
```
|
|
1300
1232
|
|
|
1233
|
+
To run unattended workers without a browser login, `agy` (1.1.13 or newer) can use
|
|
1234
|
+
a Gemini API key instead: put `"modelProvider": "gemini"` in
|
|
1235
|
+
`~/.gemini/antigravity-cli/settings.json` and set `GEMINI_API_KEY`, in your
|
|
1236
|
+
environment or in a profile's `env.GEMINI_API_KEY: ...` line (keep the key out of
|
|
1237
|
+
the repo). The key alone does nothing: without `modelProvider`, `agy` still asks
|
|
1238
|
+
you to sign in. `agy` takes no other key or token from the environment; its
|
|
1239
|
+
Google Cloud, Workforce Identity and Application Default Credentials sign-ins are
|
|
1240
|
+
chosen on its sign-in screen.
|
|
1241
|
+
|
|
1301
1242
|
Then run the whole session on it with `brindle --provider antigravity`, or mix models:
|
|
1302
1243
|
give a profile `provider: antigravity` (for example a `gemini-reviewer` for a second
|
|
1303
1244
|
model's review) and the supervisor can hand it tasks.
|
|
@@ -15,9 +15,9 @@ curl -fsSL pawdelta.com/brindle/install | sh
|
|
|
15
15
|
brindle demo # watch it finish a practice repo in a few minutes
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-

|
|
18
|
+

|
|
19
19
|
|
|
20
|
-
*`brindle demo`, recorded on brindle 0.
|
|
20
|
+
*`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.*
|
|
21
21
|
|
|
22
22
|
- **Done means a command passed.** A goal is split into milestones, each with a
|
|
23
23
|
check command that brindle runs itself. A milestone is verified when its check exits
|
|
@@ -59,13 +59,9 @@ 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.
|
|
62
|
+
session shows it too (`brindle 0.0.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
|
-
### Upgrading from copse
|
|
66
|
-
|
|
67
|
-
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.
|
|
68
|
-
|
|
69
65
|
## Quick start
|
|
70
66
|
|
|
71
67
|
```sh
|
|
@@ -315,6 +311,7 @@ your own status line prints, so what you see doesn't change.
|
|
|
315
311
|
| `brindle delegation [conservative\|balanced\|fast]` | how readily the supervisor delegates: fewest tokens, the default, or quickest |
|
|
316
312
|
| `brindle transfer [REPO] [--from SESSION] [-b BRANCH]` | move a scratch session's work into a real repo |
|
|
317
313
|
| `brindle ls [--all]` | workspaces and agents |
|
|
314
|
+
| `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") |
|
|
318
315
|
| `brindle history [--limit N] [--kind K] [--all]` | durable log of worker results, reviews, merges and milestone checks |
|
|
319
316
|
| `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 |
|
|
320
317
|
| `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") |
|
|
@@ -350,6 +347,7 @@ knowing them helps when you tell the supervisor how to work.
|
|
|
350
347
|
| `send_message` | any agent | message another agent; delivered when it's idle |
|
|
351
348
|
| `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 |
|
|
352
349
|
| `list_agents` / `list_tasks` / `list_agent_profiles` | supervisor | who's running, what's queued, which profiles exist |
|
|
350
|
+
| `list_repos` | supervisor | the repos attached to the session (brindle Pro); `repo=<alias>` on `assign`/`handoff` puts a worker there |
|
|
353
351
|
| `cancel_task` | supervisor | cancel a queued task (and its dependents) to re-plan |
|
|
354
352
|
| `workspace_diff` | supervisor | a worker branch's changes against its base |
|
|
355
353
|
| `request_review` / `submit_review` | supervisor / reviewer | start a reviewer on a branch / record its verdict |
|
|
@@ -454,7 +452,7 @@ Autopilot, merge gates and cleanup:
|
|
|
454
452
|
| `sidebar` | `"left"` | where the dashboard sits in each window: `"left"` of the chat, or `"bottom"` (full-width rows under it) |
|
|
455
453
|
| `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 |
|
|
456
454
|
| `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) |
|
|
457
|
-
| `pr_footer` | `true` | `brindle pr`
|
|
455
|
+
| `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 |
|
|
458
456
|
| `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 |
|
|
459
457
|
| `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 |
|
|
460
458
|
| `learning_candidates` | `[]` | the profile names the hosted learner may pick from |
|
|
@@ -642,8 +640,9 @@ how to use them, and the next step to get the rest:
|
|
|
642
640
|
|---|---|---|
|
|
643
641
|
| hosted learning | Pro | on by itself; `brindle learning` |
|
|
644
642
|
| per-worktree services | Pro | `"services"` in `.brindle/config.json` |
|
|
643
|
+
| several repos in one session | Pro | `brindle repo add <path>` |
|
|
645
644
|
| org policies + audit feed | Team | `brindle account org policy` |
|
|
646
|
-
| Brindle-CI | Team |
|
|
645
|
+
| Brindle-CI | Team | back in a later release |
|
|
647
646
|
| audit log, air-gap | Enterprise | `brindle audit verify`, `"airgap": true` |
|
|
648
647
|
|
|
649
648
|
```sh
|
|
@@ -659,6 +658,21 @@ brindle account org member policy-role <member> <role|none> # give a member a
|
|
|
659
658
|
brindle account org company [link <org_id> | unlink] # link orgs you own into one company; learning is pooled only within it
|
|
660
659
|
```
|
|
661
660
|
|
|
661
|
+
### Several repos in one session (brindle Pro)
|
|
662
|
+
|
|
663
|
+
A session can work across several repos. Attach another local repo you own
|
|
664
|
+
to the running session and the supervisor can put workers there: each gets a
|
|
665
|
+
worktree in that repo, that repo's own checks and review, and merges into that
|
|
666
|
+
repo's branch. A task may depend on one in another repo, a milestone check can
|
|
667
|
+
run in another repo (`check@<alias>: <command>` in `goals.md`, or `repo` in
|
|
668
|
+
`set_goal`), and the sidebar and `brindle ls` group workers by repo.
|
|
669
|
+
|
|
670
|
+
```sh
|
|
671
|
+
brindle repo add ../pawdelta-web --name web # attach a repo to the current session (alias: web)
|
|
672
|
+
brindle repo ls # the repos attached to this session
|
|
673
|
+
brindle repo rm web # detach it (its worktrees and branches stay)
|
|
674
|
+
```
|
|
675
|
+
|
|
662
676
|
Setting up a team takes no sign-up form:
|
|
663
677
|
|
|
664
678
|
```sh
|
|
@@ -762,129 +776,27 @@ brindle audit pubkey # this install's public key (
|
|
|
762
776
|
one altered in place (hash or signature), one removed, inserted or reordered
|
|
763
777
|
(seq and prev_hash), or a truncated tail. Verifying and exporting never need
|
|
764
778
|
the entitlement, so a log keeps its value after a plan lapses.
|
|
765
|
-
### Brindle-CI: issues into pull requests
|
|
766
|
-
|
|
767
|
-
brindle Team can run brindle with nobody at a terminal. `brindle ci run` cuts a
|
|
768
|
-
`brindle/ci-<issue or slug>` branch, starts a supervisor with autopilot on in a
|
|
769
|
-
detached tmux session, gives it the goal, and waits until every milestone's
|
|
770
|
-
check passes. Then it pushes the branch and opens the pull request with `gh`
|
|
771
|
-
(the body lists the goal, the milestones and their checks, and `Closes #N`
|
|
772
|
-
for an issue), prints the PR URL and exits 0; with `--bundle` it writes the
|
|
773
|
-
branch to a file instead, for `brindle ci publish` (see below). It exits 1, with what happened,
|
|
774
|
-
when the supervisor asks for a decision (`need_user`: the question is the
|
|
775
|
-
reason), stalls, or runs out of time. The session and its workers are always
|
|
776
|
-
stopped at the end, and a JSON summary goes to `$GITHUB_STEP_SUMMARY` when
|
|
777
|
-
that is set.
|
|
778
779
|
|
|
779
|
-
|
|
780
|
-
brindle ci run --issue 42 # the goal is the issue's title and body
|
|
781
|
-
brindle ci run --goal "Add a /health endpoint" # or typed; a goals.md-shaped text brings its milestones
|
|
782
|
-
brindle ci run --goal-file .brindle/goals.md --timeout 90 --max-workers 2 --base develop --no-pr
|
|
783
|
-
brindle ci init --label brindle # the GitHub Actions workflow (see below)
|
|
784
|
-
|
|
785
|
-
# The same run in three steps, so no secret worth stealing is near the agents:
|
|
786
|
-
brindle ci entitle --out ent.jwt # uses BRINDLE_PRO_TOKEN, then exits
|
|
787
|
-
brindle ci run --issue 42 --entitlement ent.jwt --bundle out/brindle.bundle # no CI token, no push token
|
|
788
|
-
brindle ci publish out/brindle.bundle --repo acme/api # elsewhere: pushes and opens the PR
|
|
789
|
-
```
|
|
780
|
+
### Brindle-CI
|
|
790
781
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
**Who is trusted with what.** Agents run your repo's code: its tests, its
|
|
797
|
-
scripts, and whatever an issue talks them into. They run as the same user as
|
|
798
|
-
brindle, so treat everything on that machine as theirs to read: environment
|
|
799
|
-
variables, files, git and `gh` settings. brindle does take its tokens out of the
|
|
800
|
-
environment before agents start and pushes from a clean copy of the commits,
|
|
801
|
-
but that only makes theft harder. What actually protects a secret is that it
|
|
802
|
-
isn't on the machine while agents run. So the work can be split:
|
|
803
|
-
|
|
804
|
-
1. `brindle ci entitle --out FILE` exchanges `BRINDLE_PRO_TOKEN` for the signed,
|
|
805
|
-
short-lived entitlement and writes it to a file (mode 0600). Run it on a
|
|
806
|
-
different machine from the agents (the workflow gives it its own job):
|
|
807
|
-
on hosted runners agents have sudo, and the runner holds every secret of
|
|
808
|
-
the job they run in. `brindle ci run` reads the file and deletes it before
|
|
809
|
-
any agent starts.
|
|
810
|
-
2. `brindle ci run --entitlement FILE --bundle PATH` does the work with no CI
|
|
811
|
-
token and no token that can write to GitHub (`--issue` needs one that can
|
|
812
|
-
read). When the goal is verified it writes the new commits to PATH as a git
|
|
813
|
-
bundle, and `PATH.json` with the branch, base, title and body of the pull
|
|
814
|
-
request. `--bundle` implies `--no-pr`: nothing is pushed.
|
|
815
|
-
3. `brindle ci publish PATH [--repo owner/name]` runs where no agent ever ran,
|
|
816
|
-
with the token that can push. It verifies the bundle, fetches its one
|
|
817
|
-
`brindle/ci-…` branch into a fresh bare repo, pushes that branch to
|
|
818
|
-
`https://github.com/<repo>` (default: `$GITHUB_REPOSITORY`) and opens the
|
|
819
|
-
pull request with `gh`. It never checks out or runs repo code, hooks or
|
|
820
|
-
agents, and it refuses a bundle whose branch isn't a `brindle/ci-` branch, so
|
|
821
|
-
a run can't publish over `main`. The pull request targets `--base`, else
|
|
822
|
-
the repository's default branch; the bundle doesn't get to choose. A
|
|
823
|
-
hostile run can still add commits to an existing `brindle/ci-` branch.
|
|
824
|
-
|
|
825
|
-
The workflow `brindle ci init` writes pins brindle to the version that wrote it,
|
|
826
|
-
since the publishing job holds a write token. The short-lived entitlement
|
|
827
|
-
passes between jobs as an artifact kept one day. A CI entitlement expires
|
|
828
|
-
three hours after it's issued, so anyone who can download the repo's
|
|
829
|
-
artifacts could use it for that long at most.
|
|
830
|
-
|
|
831
|
-
`brindle ci run` without `--bundle` still pushes and opens the pull request
|
|
832
|
-
itself. Use that only where you trust the repo's code and everyone who can
|
|
833
|
-
steer the agents.
|
|
834
|
-
|
|
835
|
-
`brindle ci init` writes `.github/workflows/brindle.yml`, which runs on
|
|
836
|
-
`workflow_dispatch` and whenever an issue gets the label (`brindle` by
|
|
837
|
-
default). It has three jobs:
|
|
838
|
-
|
|
839
|
-
- `entitle` (no permissions) runs `brindle ci entitle` with `BRINDLE_PRO_TOKEN`
|
|
840
|
-
on a machine that checks out and runs nothing from the repo. It hands the
|
|
841
|
-
short-lived entitlement (three hours) to the next job as an artifact kept
|
|
842
|
-
one day, so the CI token is never on the agents' machine.
|
|
843
|
-
- `run` (permissions: `contents: read`, `issues: read`) checks the repo out
|
|
844
|
-
without keeping credentials, installs tmux, brindle (pinned to the version
|
|
845
|
-
that wrote the workflow) and Claude Code, then runs `brindle ci run --issue
|
|
846
|
-
<number> --entitlement … --bundle …` with only `ANTHROPIC_API_KEY` and a
|
|
847
|
-
read-only `GH_TOKEN`. brindle deletes the entitlement file before any agent
|
|
848
|
-
starts. The job uploads the bundle as an artifact.
|
|
849
|
-
- `publish` (permissions:
|
|
850
|
-
`contents: write`, `pull-requests: write`) starts on a fresh machine, checks
|
|
851
|
-
nothing out, downloads the artifact and runs `brindle ci publish`, targeting
|
|
852
|
-
the repository's default branch.
|
|
853
|
-
|
|
854
|
-
`brindle ci init` won't
|
|
855
|
-
overwrite an existing file without `--force`. The workflow needs two secrets,
|
|
856
|
-
`BRINDLE_PRO_TOKEN` (an org CI token, below) and `ANTHROPIC_API_KEY`, and the
|
|
857
|
-
repo's Actions settings must allow GitHub Actions to create pull requests.
|
|
858
|
-
The model API key is the one secret agents must have; give it a spending
|
|
859
|
-
limit.
|
|
860
|
-
|
|
861
|
-
An org admin creates the CI token; it is shown once, so store it straight away:
|
|
782
|
+
Brindle-CI (brindle Team) brings brindle into your CI: it fixes broken builds,
|
|
783
|
+
turns issues into pull requests whose checks it has verified, and reviews pull
|
|
784
|
+
requests with evidence. It runs on your own CI with your own model keys; the
|
|
785
|
+
hosted control plane decides what each run does and what it reports. The
|
|
786
|
+
workflows call these commands:
|
|
862
787
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
brindle
|
|
868
|
-
|
|
788
|
+
- `brindle ci init`: set a repository up in one go (the GitHub App, the secrets,
|
|
789
|
+
the workflows as a pull request, then a doctor check).
|
|
790
|
+
- `brindle ci doctor`: which provider CLIs and credential names a runner has, and
|
|
791
|
+
which providers CI may use on this repository.
|
|
792
|
+
- `brindle ci start`: start a run for an issue, a goal text or a dispatched run,
|
|
793
|
+
or a validation of a pull request.
|
|
794
|
+
- `brindle ci run`: run what was started: the supervisor and the result upload,
|
|
795
|
+
or the pull request's checks and reviews and the evidence upload.
|
|
796
|
+
- `brindle ci report`: tell the service how the workflow's jobs ended.
|
|
869
797
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
memory and writes nothing to disk; `brindle ci entitle` writes only the signed
|
|
873
|
-
entitlement, which expires soon, never the token. The token doesn't rotate, so one secret
|
|
874
|
-
keeps working until it is revoked or the org's plan no longer includes CI. A
|
|
875
|
-
refresh token from `brindle account login` won't do: it rotates on use.
|
|
876
|
-
|
|
877
|
-
Two things to know before you add the label to your repo:
|
|
878
|
-
|
|
879
|
-
- **Who can apply the label.** The issue body steers an unattended agent
|
|
880
|
-
whose work becomes a pull request on a `brindle/ci-` branch. Only people you
|
|
881
|
-
trust with write access should be able to apply the trigger label; on a
|
|
882
|
-
public repo, anyone who can write the issue text is choosing what the agent
|
|
883
|
-
is told to do. Review the pull request like any other before merging it.
|
|
884
|
-
- **CI on the pull request.** A PR opened with the workflow's own
|
|
885
|
-
`GITHUB_TOKEN` doesn't trigger the repo's other workflows. If you want your
|
|
886
|
-
checks to run on brindle's PRs, set `GH_TOKEN` in the `publish` job to a
|
|
887
|
-
GitHub App installation token or a personal access token instead.
|
|
798
|
+
Credential names are reported, never values. On a repository owned by a GitHub
|
|
799
|
+
organization, a provider signed in only with a personal subscription is not used.
|
|
888
800
|
|
|
889
801
|
**Closing and cleaning up.** Press `x` on an agent in the sidebar (twice for one
|
|
890
802
|
that's still running) or run `brindle close <id>` to stop it and hide it. Stopping means
|
|
@@ -1026,14 +938,34 @@ change files under a directory without prompts.
|
|
|
1026
938
|
brindle only offers a profile whose CLI is installed and signed in. A profile on a
|
|
1027
939
|
CLI that isn't signed in is left out of the supervisor's profile list and of
|
|
1028
940
|
routing by weight, and naming it directly stops with how to sign in
|
|
1029
|
-
(`claude auth login`, `codex login`) instead of opening the CLI's
|
|
1030
|
-
`brindle doctor` shows each CLI's
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
941
|
+
(`claude auth login`, `codex login`, running `agy`) instead of opening the CLI's
|
|
942
|
+
login screen. `brindle doctor` shows, for each installed CLI, how it's signed in
|
|
943
|
+
and whether a quota limit is in effect. Sign-in is its own login, an environment
|
|
944
|
+
key (by name, never its value) set in your shell or in a profile's
|
|
945
|
+
`env.NAME: value` lines, signed out, or unknown when the status check gives no
|
|
946
|
+
answer. Keys set in the environment (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
|
|
947
|
+
`GEMINI_API_KEY` and the like) count as signed in; see the table below for what
|
|
948
|
+
each CLI takes. A worker that no hook reports on (Codex)
|
|
1034
949
|
and that shows nothing new for 10 minutes without reporting, for example because
|
|
1035
950
|
it's signed in without a plan that includes it, is reported to its supervisor.
|
|
1036
951
|
|
|
952
|
+
#### Key login
|
|
953
|
+
|
|
954
|
+
| Provider | Key login (environment variables) |
|
|
955
|
+
|---|---|
|
|
956
|
+
| `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`) |
|
|
957
|
+
| `codex` | yes: `OPENAI_API_KEY`, `CODEX_API_KEY` |
|
|
958
|
+
| `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 |
|
|
959
|
+
|
|
960
|
+
Workers that run unattended should use key login where the CLI supports it.
|
|
961
|
+
A personal login is one interactive session with one quota shared by every
|
|
962
|
+
worker: when it expires or its quota runs out, every worker on it stalls until
|
|
963
|
+
someone signs in again in a browser. A key gives workers their own limits and
|
|
964
|
+
needs no browser step. Put the key in your environment, or in a profile's
|
|
965
|
+
`env.NAME: value` lines in `~/.brindle/agents` (never in the repo), and
|
|
966
|
+
`brindle doctor` names the variable each CLI gets, from your shell or from
|
|
967
|
+
which profiles.
|
|
968
|
+
|
|
1037
969
|
### Cheap workers
|
|
1038
970
|
|
|
1039
971
|
By default a Claude Code worker loads everything your own `claude` does: your
|
|
@@ -1268,6 +1200,15 @@ curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
|
1268
1200
|
agy # sign in with your Google account, then quit
|
|
1269
1201
|
```
|
|
1270
1202
|
|
|
1203
|
+
To run unattended workers without a browser login, `agy` (1.1.13 or newer) can use
|
|
1204
|
+
a Gemini API key instead: put `"modelProvider": "gemini"` in
|
|
1205
|
+
`~/.gemini/antigravity-cli/settings.json` and set `GEMINI_API_KEY`, in your
|
|
1206
|
+
environment or in a profile's `env.GEMINI_API_KEY: ...` line (keep the key out of
|
|
1207
|
+
the repo). The key alone does nothing: without `modelProvider`, `agy` still asks
|
|
1208
|
+
you to sign in. `agy` takes no other key or token from the environment; its
|
|
1209
|
+
Google Cloud, Workforce Identity and Application Default Credentials sign-ins are
|
|
1210
|
+
chosen on its sign-in screen.
|
|
1211
|
+
|
|
1271
1212
|
Then run the whole session on it with `brindle --provider antigravity`, or mix models:
|
|
1272
1213
|
give a profile `provider: antigravity` (for example a `gemini-reviewer` for a second
|
|
1273
1214
|
model's review) and the supervisor can hand it tasks.
|