brindle 0.4.7__tar.gz → 0.5.1__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.4.7 → brindle-0.5.1}/PKG-INFO +68 -74
- {brindle-0.4.7 → brindle-0.5.1}/README.md +67 -73
- {brindle-0.4.7 → brindle-0.5.1}/pyproject.toml +2 -2
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/__main__.py +2 -2
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/agents.py +304 -169
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/antigravity.py +12 -15
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/autopilot.py +11 -9
- brindle-0.5.1/src/brindle/builtin_agents/developer-codex.md +9 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/reviewer-codex.md +3 -1
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/reviewer.md +1 -1
- brindle-0.5.1/src/brindle/bus.py +149 -0
- brindle-0.5.1/src/brindle/check_scope.py +313 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/cli.py +39 -7
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/codemap.py +99 -58
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/codex_hook.py +4 -7
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/config.py +15 -8
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/cull.py +13 -12
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/api-schema.json +2804 -2456
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/app.py +1 -4
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/events.py +4 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/holds.py +150 -17
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/routes_actions.py +232 -26
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/routes_read.py +41 -12
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/db.py +78 -4
- brindle-0.5.1/src/brindle/entry.py +25 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/gates.py +48 -15
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/mcp_server.py +12 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/permissions.py +2 -1
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/runner.py +11 -9
- brindle-0.5.1/src/brindle/permission_asks.py +184 -0
- brindle-0.5.1/src/brindle/permission_grants.py +803 -0
- brindle-0.5.1/src/brindle/permission_groups.py +458 -0
- brindle-0.5.1/src/brindle/permission_routing.py +167 -0
- brindle-0.5.1/src/brindle/permissions.py +4069 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pipeline.py +33 -18
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/_files.py +11 -6
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/license.py +148 -6
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/profiles.py +18 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/prompt_answer.py +22 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/providers.py +31 -5
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/quota.py +6 -2
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/service/dto.py +191 -117
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/service/inbox.py +17 -137
- brindle-0.5.1/src/brindle/service/permissions.py +138 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/watch.py +8 -1
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/workspaces.py +9 -5
- brindle-0.4.7/src/brindle/builtin_agents/developer-codex.md +0 -6
- brindle-0.4.7/src/brindle/bus.py +0 -75
- brindle-0.4.7/src/brindle/daemon/grants.py +0 -320
- brindle-0.4.7/src/brindle/daemon/routes_permissions.py +0 -37
- brindle-0.4.7/src/brindle/permission_editor.py +0 -385
- brindle-0.4.7/src/brindle/permission_grants.py +0 -646
- brindle-0.4.7/src/brindle/permission_presets.json +0 -44
- brindle-0.4.7/src/brindle/permissions.py +0 -2182
- {brindle-0.4.7 → brindle-0.5.1}/.gitignore +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/LICENSE +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/SCHEDULE-A +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/account.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/airgap.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/assembler.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/assets/braid_dark.png +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/assets/braid_light.png +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/budget.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/backend-auditor.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/coordinator.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-fable.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-gemini.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-heavy.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-light.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-local.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-opencode.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer-sonnet.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/developer.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/qa.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/reviewer-gemini.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/reviewer-local.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/reviewer-opencode.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/subagent.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_agents/supervisor.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_rules/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_rules/security/backend.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_rules/style/minimal-diff.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/builtin_rules/tests/only.md +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/ci_adapters.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/ci_client.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/ci_federation.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/ci_hosts.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/clone.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/cloud_credential.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/cloud_login.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/codemap_docs.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/company_identity.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/company_login.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/conflicts.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/coordinator.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/cost.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/cost_estimate.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/auth.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/lifecycle.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/peer.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/routes_org_permissions.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/schema.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/session_review.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/daemon/terminal.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/debuglog.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/demo.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/detect.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/doctor.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/escapes.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/events.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/git.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/guardrails.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/history.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/identity_lock.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/inbox.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/kb.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/key_check.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/keys_cmds.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/keystore.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/knowledge.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/launch_health.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/learned_rules.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/learning.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/legacy.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/local_setup.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/login_pause.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/model_access.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/model_availability.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/catalog.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/client.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/loop.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/lsp.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/serve.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/native/tools.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/opencode.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/org_permissions.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pane_auth.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/picker.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/plugins.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/policy.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pool.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/preflight.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pricing.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/account.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/audit_chain.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/audit_export.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/auth.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/brief_learning.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/cost_centers.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/credentials.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/features.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/keys.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/learning.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/loopback.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/managed_models.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/org_profiles.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/orgkey.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/rollout.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/route_health.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/settings_sync.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/status.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/team_events.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/pro/team_policy.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/procs.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/provider_homes.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/providers_install.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/repo_cmds.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/repos.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/rewind.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/rule_checks.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/savings.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/scratch.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/secrets.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/self_serve.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/service/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/service/errors.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/service/routing.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/service/sessions.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/services.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/sessions.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/sidebar_follow.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/sidebar_logo.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/signin_pause.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/status_cache.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/tasks.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/tmux.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/updates.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/upgrade.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/usage.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/view.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/wake.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/watch_costs.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/__init__.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/chat.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/dashboard.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/diff.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/server.py +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/static/app.js +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/web/static/index.html +0 -0
- {brindle-0.4.7 → brindle-0.5.1}/src/brindle/worker_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brindle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
@@ -404,7 +404,7 @@ your own status line prints, so what you see doesn't change.
|
|
|
404
404
|
| `brindle cost [--days N] [--all]` | dollar spend at list prices over the last 30 days, by model |
|
|
405
405
|
| `brindle cost report [--days N] [--all]` | Pro: spend by day, profile and goal, cost per merged branch, review pass rate per worker profile |
|
|
406
406
|
| `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 |
|
|
407
|
-
| `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") |
|
|
407
|
+
| `brindle permissions list / check / preset / suggestions / accept / allow / deny / forget / reset` | the rules brindle answers workers' permission requests with, the preset they started from, and what it suggests from your approvals (see "Permission policy"; saved actions are managed in the app for now, [#285](https://github.com/PawDelta/brindle/issues/285)) |
|
|
408
408
|
| `brindle permissions install-codex-hook [--yes]` / `brindle permissions sync-agy` | trust brindle's Codex permission hook now (brindle does it itself when needed); copy your rules into Antigravity's settings (see "Permission policy") |
|
|
409
409
|
| `brindle cost request --usd N --reason "..." [--goal TEXT]` | Enterprise (cost centers): ask an admin to approve spend over your budget. A budget refusal points here. Once approved, this month's limit (or the named goal's) goes up by the approved amount, for the month it was approved in |
|
|
410
410
|
| `brindle cost requests` | Enterprise: your approval requests and their status; checks pending ones with the server (the cull pass also does, every few minutes). With cost centers, spend events also carry the repo (`owner/name`) so the org can total spend per center |
|
|
@@ -473,6 +473,7 @@ knowing them helps when you tell the supervisor how to work.
|
|
|
473
473
|
| `report_result` | worker | finish a task and hand back the result |
|
|
474
474
|
| `submit_plan` | worker | a `plan_first` worker proposes its plan and waits for approval before editing |
|
|
475
475
|
| `approve_plan` | supervisor | approve a worker's plan, or send it back with feedback (`approved=false`) |
|
|
476
|
+
| `answer_permission` | supervisor | allow, deny or escalate (with a reason) a worker's permission ask before the person sees it |
|
|
476
477
|
| `complete_subagent` | supervisor | record the result of a `subagent`-profile task |
|
|
477
478
|
| `set_goal` / `get_progress` / `check_milestone` | supervisor | autopilot's goal, its progress, and running the checks |
|
|
478
479
|
| `record_audit_decision` | supervisor | record acceptance of an audit finding with rationale so subsequent audits respect it |
|
|
@@ -672,7 +673,8 @@ Autopilot, merge gates and cleanup:
|
|
|
672
673
|
| `autopilot` | `true` | start the supervisor with autopilot on |
|
|
673
674
|
| `claude_permission_mode` | `"default"` | the `--permission-mode` for Claude Code sessions whose profile sets no `permission_mode`; the default holds permission requests for the brindle app, set `"auto"` to opt into auto mode. Only read from `~/.brindle/config.json` |
|
|
674
675
|
| `auto_update` | `false` | run `uv tool upgrade brindle` in the background at session start when PyPI has a newer version; restart to use it. Can also be set in `~/.brindle/config.json` for every repo |
|
|
675
|
-
| `
|
|
676
|
+
| `scoped_checks` | unset (acts as `"off"`) | `"infer"` narrows a bare pytest check (`pytest ...`, `python -m pytest ...`, `uv run pytest ...`, options only) on a worker's branch to the tests `graphify affected` reaches plus the touched test files, when the repo has a stored graph; it runs in full when the mapping fails or `conftest.py`, `pyproject.toml`, `setup.cfg`, `pytest.ini`, `tox.ini` or a lockfile changed. A pytest command that already names test paths (`pytest tests/`) and every other command always run in full. `"off"` narrows nothing. It becomes the default next release; until you set it, brindle tells you once |
|
|
677
|
+
| `checks` | `[]` | commands (plain strings) that must pass in a worker's branch before it merges. On a worker's branch every check also gets `BRINDLE_CHANGED_FILES` (the files changed since the branch left its base, one repo-relative path per line) so a script can narrow itself; the supervisor's checkout always runs every check in full (see `scoped_checks` and `brindle/check_scope.py`) |
|
|
676
678
|
| `review` | only under autopilot | require a reviewer's approval before merging |
|
|
677
679
|
| `reviewer` | `"reviewer"` | the agent profile that reviews (a Codex profile gives a second model's view) |
|
|
678
680
|
| `review_profile` | none | force `request_review`'s profile, skipping its automatic cross-model pick (see below) |
|
|
@@ -691,7 +693,8 @@ Autopilot, merge gates and cleanup:
|
|
|
691
693
|
| `goal_audit` | `true` | once every milestone passes, an adversarial reviewer checks the work against the original goal before the goal counts as reached |
|
|
692
694
|
| `merge_into` | none | branch that worker branches are cut from and merge into, whatever branch the supervisor is on |
|
|
693
695
|
| `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) |
|
|
694
|
-
| `permission_policy` | `"off"` | `"on"`: brindle answers
|
|
696
|
+
| `permission_policy` | `"on"` with a Pro license, else `"off"` | `"on"`: brindle answers workers' permission requests from its rules (see "Permission policy" below); `"off"`: the provider's own prompts and permission mode decide, except Antigravity workers under `agy_approvals: "brindle"`, whose hook still enforces the rules. The only permission switch: a leftover `permission_essentials` key is ignored |
|
|
697
|
+
| `permission_supervisor_hold_seconds` | `120` | with `permission_policy` on, how long a Claude Code or Codex worker's ask waits on its supervisor (`answer_permission`) before you see it; asks a person-only rule makes (pushes into the default or a release branch) come straight to you |
|
|
695
698
|
| `agy_approvals` | unset | `"brindle"`: Antigravity agents run without approval prompts and brindle's hook allows or denies every call, applying the profile's `allowed_tools` (see "Antigravity" under "Permission policy"); `"prompt"`: agy asks as usual. Unset, workers get `"brindle"` and interactive agy sessions `"prompt"` |
|
|
696
699
|
| `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 |
|
|
697
700
|
| `plan_first` | `false` | workers propose a plan (`submit_plan`) and wait for `approve_plan` before editing |
|
|
@@ -879,26 +882,43 @@ command, path or URL; brindle never reads the screen) and brindle answers
|
|
|
879
882
|
**allow**, **deny**, or **ask**, which leaves the prompt to you as usual. Any
|
|
880
883
|
error is ask.
|
|
881
884
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
- **
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
`
|
|
897
|
-
|
|
898
|
-
|
|
885
|
+
Nothing is built in. Every rule lives in `~/.brindle/permissions.json`, and
|
|
886
|
+
you can edit or remove any of them, including the ones a **preset** seeded.
|
|
887
|
+
Pick a preset in Settings → Permissions or at setup:
|
|
888
|
+
|
|
889
|
+
- **Autonomous** (the default): everything runs, except pushes into the
|
|
890
|
+
repo's default branch (ask) and destructive actions (deny: git force flags,
|
|
891
|
+
deleting a branch by push, a recursive `rm` of `/`, a top-level folder or
|
|
892
|
+
home);
|
|
893
|
+
- **Permissive**: edits in the worktree and everyday commands run, the rest asks;
|
|
894
|
+
- **Standard**: routine reads and everyday commands run, changes ask;
|
|
895
|
+
- **Secure**: short approvals, and a deny for anything no rule covers.
|
|
896
|
+
|
|
897
|
+
Every preset also denies reading `~/.ssh`, `~/.aws`, `~/.gnupg`, `.env*` and
|
|
898
|
+
the daemon's token, and asks before every push into a `release` or
|
|
899
|
+
`release/*` branch, which starts a signed build (an approval there is never
|
|
900
|
+
saved). It allows reading files git tracks, the repo's `checks`, read-only
|
|
901
|
+
git commands and read-only pipelines (grep, rg, ls, cat, head, `sed -n` ...
|
|
902
|
+
joined by pipes or `&&`, quoting read as the shell reads it). A pipeline
|
|
903
|
+
stops being read-only when it writes a file, substitutes a command, sets a
|
|
904
|
+
variable, recurses into a tree with a file a read deny covers, or reads such a
|
|
905
|
+
file. Precedence: a deny wins, then an ask, then an allow, then the preset's
|
|
906
|
+
setting for what no rule covers (ask, allow or deny). A deny or ask also
|
|
907
|
+
catches a part of a compound command however it's spelled (spacing, quotes,
|
|
908
|
+
assignments, redirects, `$(...)`, patterns the shell expands); when brindle
|
|
909
|
+
can't read the syntax and a deny or ask could match it, it asks.
|
|
910
|
+
|
|
911
|
+
Add your own with `brindle permissions allow|deny KIND MATCH` (kinds: `read`,
|
|
912
|
+
`write`, `edit`, `bash`, `fetch`, `mcp`, `other`; the match is exact unless
|
|
913
|
+
`--prefix` or `--glob`) or in the app, which can also make ask rules with
|
|
914
|
+
limits on saved approvals, timed rules and exceptions. A repo's
|
|
899
915
|
`.brindle/permissions.json` (`{"rules": [...]}`, same format) can only add
|
|
900
916
|
denies. `brindle permissions list` shows every rule and where it came from,
|
|
901
|
-
`forget ID` removes one
|
|
917
|
+
`forget ID` removes one, `reset` goes back to the preset's rules. A store
|
|
918
|
+
written by brindle 0.4.7 is migrated on first load: its permission editor's
|
|
919
|
+
preset becomes Permissive, Standard or Secure (Autonomous when it chose
|
|
920
|
+
none), its own rules stay, and its remembered approvals become saved actions;
|
|
921
|
+
its old rows stay in the file.
|
|
902
922
|
Profiles can add narrower, profile-local denies with a JSON array in frontmatter,
|
|
903
923
|
for example `permission_denies: ["read glob ~/.private*", "bash prefix deploy"]`.
|
|
904
924
|
Built-in profiles ship with no profile-specific denies by default. These denies
|
|
@@ -919,63 +939,37 @@ on without the tool running counts for nothing. Every decision is in
|
|
|
919
939
|
`brindle history --kind permission`, and when a worker sits on a prompt, its
|
|
920
940
|
supervisor is told exactly which request is pending (only you can answer it).
|
|
921
941
|
|
|
922
|
-
**
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
**Remembered approvals** are saved in your user permission preferences, across
|
|
943
|
-
sessions and daemon restarts, until you revoke them in Settings → Permission
|
|
944
|
-
grants. A remembered push covers the same repository, remote URL and destination
|
|
945
|
-
branch across future commits; a file approval covers that specific file.
|
|
946
|
-
Every use still checks the current policy, explicit denies and adapter protections.
|
|
947
|
-
Temporary time/use limits apply to temporary grants; persistent approvals require
|
|
948
|
-
their own policy permission. Turning that permission off prevents their use.
|
|
949
|
-
- `git push` qualifies only as `git push <remote> <full commit sha>:refs/heads/<branch>`, run in the agent's own worktree (not another clone or a nested repository), and only when:
|
|
950
|
-
- the remote resolves (insteadOf applied) to exactly one https, ssh or `user@host:path` URL;
|
|
951
|
-
- none of `core.sshCommand`, `core.hooksPath`, the remote's receivepack/vcs/mirror, `push.followTags` or `push.recurseSubmodules` is set;
|
|
952
|
-
- there is no pre-push or reference-transaction hook;
|
|
953
|
-
- neither the repo nor your org sets protected paths (a push skips the merge check that enforces them).
|
|
954
|
-
- `.env*` qualifies for one file inside the worktree.
|
|
955
|
-
|
|
956
|
-
After your answer, brindle checks the policy, every rule and that scope again
|
|
957
|
-
before allowing. Anything that changed meanwhile refuses it. The command then
|
|
958
|
-
runs outside brindle.
|
|
959
|
-
|
|
960
|
-
Never lifted: your own, the repo's, a profile's or your org's denies, git force
|
|
961
|
-
flags, and reads of `~/.ssh`, `~/.aws`, `~/.gnupg` or the daemon's token.
|
|
962
|
-
Antigravity and OpenCode workers get no grants: agy ignores a hook's allow, and
|
|
963
|
-
OpenCode's plugin has no hold.
|
|
964
|
-
|
|
965
|
-
In a Team org, only the org policy's `permission_grants` block decides what may
|
|
966
|
-
be granted. It is read again on every request:
|
|
942
|
+
**Saved actions.** The app's Inbox groups pending asks by kind and general
|
|
943
|
+
form (a push by its destination, a file by its top folder, a command by its
|
|
944
|
+
first two words, an MCP tool or its server). One decision answers the group:
|
|
945
|
+
once, for the session, for a time, until revoked, deny, or always deny. Anything
|
|
946
|
+
kept is a saved action, listed and editable under Settings → Permissions. A
|
|
947
|
+
saved deny stops every ask it covers. A saved allow settles an ask only within
|
|
948
|
+
the limits of the ask rule that asked (its scope and how long approvals may
|
|
949
|
+
last), never past a deny rule, and never once it has expired. Every use reads
|
|
950
|
+
the current rules again.
|
|
951
|
+
|
|
952
|
+
Saved actions and the grouped Inbox are in the app only for now. From the
|
|
953
|
+
CLI, saved actions still apply to every worker, but you can't list, edit or
|
|
954
|
+
delete one (`brindle permissions reset` removes them all, with your own and
|
|
955
|
+
learned rules), and without the app a held request falls back to the worker
|
|
956
|
+
CLI's own prompt in its pane, one exact request at a time. CLI commands for
|
|
957
|
+
both are tracked in
|
|
958
|
+
[#285](https://github.com/PawDelta/brindle/issues/285).
|
|
959
|
+
|
|
960
|
+
In a Team org, the org policy's `permission_grants` block bounds what a saved
|
|
961
|
+
allow may do. It is read again on every request:
|
|
967
962
|
|
|
968
963
|
```json
|
|
969
|
-
"permission_grants": {"allow": true, "kinds": ["bash", "fetch"], "
|
|
970
|
-
"
|
|
971
|
-
"deny": ["bash prefix terraform apply"]}
|
|
964
|
+
"permission_grants": {"allow": true, "kinds": ["bash", "fetch"], "max_minutes": 30,
|
|
965
|
+
"allow_persistent": true, "lifetimes": ["session", "time", "forever"],
|
|
966
|
+
"scopes": ["branch", "remote"], "deny": ["bash prefix terraform apply"]}
|
|
972
967
|
```
|
|
973
968
|
|
|
974
969
|
- `deny` entries are enforced for every provider and can't be lifted.
|
|
975
|
-
-
|
|
976
|
-
- A policy without the block,
|
|
977
|
-
-
|
|
978
|
-
- The org backend that serves this block isn't part of this repository. Until it serves one, Team orgs get no grants. It is enforced from the cached policy, or in air-gap mode from `.brindle/policy.json`.
|
|
970
|
+
- A saved allow applies only for the listed `kinds`, `lifetimes` and `scopes`, with timed ones capped at `max_minutes`; one that lasts until revoked also needs `allow_persistent`.
|
|
971
|
+
- A policy without the block, one that can't be read, or a paused or shut-down member: no saved allow applies.
|
|
972
|
+
- Org admins edit the block in Settings → Organization approvals. It is enforced from the cached policy, or in air-gap mode from `.brindle/policy.json`.
|
|
979
973
|
|
|
980
974
|
**Codex.** Codex runs a hook only once it's trusted, so with
|
|
981
975
|
`permission_policy` on, brindle trusts its own hook the first time a Codex worker
|
|
@@ -372,7 +372,7 @@ your own status line prints, so what you see doesn't change.
|
|
|
372
372
|
| `brindle cost [--days N] [--all]` | dollar spend at list prices over the last 30 days, by model |
|
|
373
373
|
| `brindle cost report [--days N] [--all]` | Pro: spend by day, profile and goal, cost per merged branch, review pass rate per worker profile |
|
|
374
374
|
| `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 |
|
|
375
|
-
| `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") |
|
|
375
|
+
| `brindle permissions list / check / preset / suggestions / accept / allow / deny / forget / reset` | the rules brindle answers workers' permission requests with, the preset they started from, and what it suggests from your approvals (see "Permission policy"; saved actions are managed in the app for now, [#285](https://github.com/PawDelta/brindle/issues/285)) |
|
|
376
376
|
| `brindle permissions install-codex-hook [--yes]` / `brindle permissions sync-agy` | trust brindle's Codex permission hook now (brindle does it itself when needed); copy your rules into Antigravity's settings (see "Permission policy") |
|
|
377
377
|
| `brindle cost request --usd N --reason "..." [--goal TEXT]` | Enterprise (cost centers): ask an admin to approve spend over your budget. A budget refusal points here. Once approved, this month's limit (or the named goal's) goes up by the approved amount, for the month it was approved in |
|
|
378
378
|
| `brindle cost requests` | Enterprise: your approval requests and their status; checks pending ones with the server (the cull pass also does, every few minutes). With cost centers, spend events also carry the repo (`owner/name`) so the org can total spend per center |
|
|
@@ -441,6 +441,7 @@ knowing them helps when you tell the supervisor how to work.
|
|
|
441
441
|
| `report_result` | worker | finish a task and hand back the result |
|
|
442
442
|
| `submit_plan` | worker | a `plan_first` worker proposes its plan and waits for approval before editing |
|
|
443
443
|
| `approve_plan` | supervisor | approve a worker's plan, or send it back with feedback (`approved=false`) |
|
|
444
|
+
| `answer_permission` | supervisor | allow, deny or escalate (with a reason) a worker's permission ask before the person sees it |
|
|
444
445
|
| `complete_subagent` | supervisor | record the result of a `subagent`-profile task |
|
|
445
446
|
| `set_goal` / `get_progress` / `check_milestone` | supervisor | autopilot's goal, its progress, and running the checks |
|
|
446
447
|
| `record_audit_decision` | supervisor | record acceptance of an audit finding with rationale so subsequent audits respect it |
|
|
@@ -640,7 +641,8 @@ Autopilot, merge gates and cleanup:
|
|
|
640
641
|
| `autopilot` | `true` | start the supervisor with autopilot on |
|
|
641
642
|
| `claude_permission_mode` | `"default"` | the `--permission-mode` for Claude Code sessions whose profile sets no `permission_mode`; the default holds permission requests for the brindle app, set `"auto"` to opt into auto mode. Only read from `~/.brindle/config.json` |
|
|
642
643
|
| `auto_update` | `false` | run `uv tool upgrade brindle` in the background at session start when PyPI has a newer version; restart to use it. Can also be set in `~/.brindle/config.json` for every repo |
|
|
643
|
-
| `
|
|
644
|
+
| `scoped_checks` | unset (acts as `"off"`) | `"infer"` narrows a bare pytest check (`pytest ...`, `python -m pytest ...`, `uv run pytest ...`, options only) on a worker's branch to the tests `graphify affected` reaches plus the touched test files, when the repo has a stored graph; it runs in full when the mapping fails or `conftest.py`, `pyproject.toml`, `setup.cfg`, `pytest.ini`, `tox.ini` or a lockfile changed. A pytest command that already names test paths (`pytest tests/`) and every other command always run in full. `"off"` narrows nothing. It becomes the default next release; until you set it, brindle tells you once |
|
|
645
|
+
| `checks` | `[]` | commands (plain strings) that must pass in a worker's branch before it merges. On a worker's branch every check also gets `BRINDLE_CHANGED_FILES` (the files changed since the branch left its base, one repo-relative path per line) so a script can narrow itself; the supervisor's checkout always runs every check in full (see `scoped_checks` and `brindle/check_scope.py`) |
|
|
644
646
|
| `review` | only under autopilot | require a reviewer's approval before merging |
|
|
645
647
|
| `reviewer` | `"reviewer"` | the agent profile that reviews (a Codex profile gives a second model's view) |
|
|
646
648
|
| `review_profile` | none | force `request_review`'s profile, skipping its automatic cross-model pick (see below) |
|
|
@@ -659,7 +661,8 @@ Autopilot, merge gates and cleanup:
|
|
|
659
661
|
| `goal_audit` | `true` | once every milestone passes, an adversarial reviewer checks the work against the original goal before the goal counts as reached |
|
|
660
662
|
| `merge_into` | none | branch that worker branches are cut from and merge into, whatever branch the supervisor is on |
|
|
661
663
|
| `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) |
|
|
662
|
-
| `permission_policy` | `"off"` | `"on"`: brindle answers
|
|
664
|
+
| `permission_policy` | `"on"` with a Pro license, else `"off"` | `"on"`: brindle answers workers' permission requests from its rules (see "Permission policy" below); `"off"`: the provider's own prompts and permission mode decide, except Antigravity workers under `agy_approvals: "brindle"`, whose hook still enforces the rules. The only permission switch: a leftover `permission_essentials` key is ignored |
|
|
665
|
+
| `permission_supervisor_hold_seconds` | `120` | with `permission_policy` on, how long a Claude Code or Codex worker's ask waits on its supervisor (`answer_permission`) before you see it; asks a person-only rule makes (pushes into the default or a release branch) come straight to you |
|
|
663
666
|
| `agy_approvals` | unset | `"brindle"`: Antigravity agents run without approval prompts and brindle's hook allows or denies every call, applying the profile's `allowed_tools` (see "Antigravity" under "Permission policy"); `"prompt"`: agy asks as usual. Unset, workers get `"brindle"` and interactive agy sessions `"prompt"` |
|
|
664
667
|
| `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 |
|
|
665
668
|
| `plan_first` | `false` | workers propose a plan (`submit_plan`) and wait for `approve_plan` before editing |
|
|
@@ -847,26 +850,43 @@ command, path or URL; brindle never reads the screen) and brindle answers
|
|
|
847
850
|
**allow**, **deny**, or **ask**, which leaves the prompt to you as usual. Any
|
|
848
851
|
error is ask.
|
|
849
852
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
- **
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
`
|
|
865
|
-
|
|
866
|
-
|
|
853
|
+
Nothing is built in. Every rule lives in `~/.brindle/permissions.json`, and
|
|
854
|
+
you can edit or remove any of them, including the ones a **preset** seeded.
|
|
855
|
+
Pick a preset in Settings → Permissions or at setup:
|
|
856
|
+
|
|
857
|
+
- **Autonomous** (the default): everything runs, except pushes into the
|
|
858
|
+
repo's default branch (ask) and destructive actions (deny: git force flags,
|
|
859
|
+
deleting a branch by push, a recursive `rm` of `/`, a top-level folder or
|
|
860
|
+
home);
|
|
861
|
+
- **Permissive**: edits in the worktree and everyday commands run, the rest asks;
|
|
862
|
+
- **Standard**: routine reads and everyday commands run, changes ask;
|
|
863
|
+
- **Secure**: short approvals, and a deny for anything no rule covers.
|
|
864
|
+
|
|
865
|
+
Every preset also denies reading `~/.ssh`, `~/.aws`, `~/.gnupg`, `.env*` and
|
|
866
|
+
the daemon's token, and asks before every push into a `release` or
|
|
867
|
+
`release/*` branch, which starts a signed build (an approval there is never
|
|
868
|
+
saved). It allows reading files git tracks, the repo's `checks`, read-only
|
|
869
|
+
git commands and read-only pipelines (grep, rg, ls, cat, head, `sed -n` ...
|
|
870
|
+
joined by pipes or `&&`, quoting read as the shell reads it). A pipeline
|
|
871
|
+
stops being read-only when it writes a file, substitutes a command, sets a
|
|
872
|
+
variable, recurses into a tree with a file a read deny covers, or reads such a
|
|
873
|
+
file. Precedence: a deny wins, then an ask, then an allow, then the preset's
|
|
874
|
+
setting for what no rule covers (ask, allow or deny). A deny or ask also
|
|
875
|
+
catches a part of a compound command however it's spelled (spacing, quotes,
|
|
876
|
+
assignments, redirects, `$(...)`, patterns the shell expands); when brindle
|
|
877
|
+
can't read the syntax and a deny or ask could match it, it asks.
|
|
878
|
+
|
|
879
|
+
Add your own with `brindle permissions allow|deny KIND MATCH` (kinds: `read`,
|
|
880
|
+
`write`, `edit`, `bash`, `fetch`, `mcp`, `other`; the match is exact unless
|
|
881
|
+
`--prefix` or `--glob`) or in the app, which can also make ask rules with
|
|
882
|
+
limits on saved approvals, timed rules and exceptions. A repo's
|
|
867
883
|
`.brindle/permissions.json` (`{"rules": [...]}`, same format) can only add
|
|
868
884
|
denies. `brindle permissions list` shows every rule and where it came from,
|
|
869
|
-
`forget ID` removes one
|
|
885
|
+
`forget ID` removes one, `reset` goes back to the preset's rules. A store
|
|
886
|
+
written by brindle 0.4.7 is migrated on first load: its permission editor's
|
|
887
|
+
preset becomes Permissive, Standard or Secure (Autonomous when it chose
|
|
888
|
+
none), its own rules stay, and its remembered approvals become saved actions;
|
|
889
|
+
its old rows stay in the file.
|
|
870
890
|
Profiles can add narrower, profile-local denies with a JSON array in frontmatter,
|
|
871
891
|
for example `permission_denies: ["read glob ~/.private*", "bash prefix deploy"]`.
|
|
872
892
|
Built-in profiles ship with no profile-specific denies by default. These denies
|
|
@@ -887,63 +907,37 @@ on without the tool running counts for nothing. Every decision is in
|
|
|
887
907
|
`brindle history --kind permission`, and when a worker sits on a prompt, its
|
|
888
908
|
supervisor is told exactly which request is pending (only you can answer it).
|
|
889
909
|
|
|
890
|
-
**
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
**Remembered approvals** are saved in your user permission preferences, across
|
|
911
|
-
sessions and daemon restarts, until you revoke them in Settings → Permission
|
|
912
|
-
grants. A remembered push covers the same repository, remote URL and destination
|
|
913
|
-
branch across future commits; a file approval covers that specific file.
|
|
914
|
-
Every use still checks the current policy, explicit denies and adapter protections.
|
|
915
|
-
Temporary time/use limits apply to temporary grants; persistent approvals require
|
|
916
|
-
their own policy permission. Turning that permission off prevents their use.
|
|
917
|
-
- `git push` qualifies only as `git push <remote> <full commit sha>:refs/heads/<branch>`, run in the agent's own worktree (not another clone or a nested repository), and only when:
|
|
918
|
-
- the remote resolves (insteadOf applied) to exactly one https, ssh or `user@host:path` URL;
|
|
919
|
-
- none of `core.sshCommand`, `core.hooksPath`, the remote's receivepack/vcs/mirror, `push.followTags` or `push.recurseSubmodules` is set;
|
|
920
|
-
- there is no pre-push or reference-transaction hook;
|
|
921
|
-
- neither the repo nor your org sets protected paths (a push skips the merge check that enforces them).
|
|
922
|
-
- `.env*` qualifies for one file inside the worktree.
|
|
923
|
-
|
|
924
|
-
After your answer, brindle checks the policy, every rule and that scope again
|
|
925
|
-
before allowing. Anything that changed meanwhile refuses it. The command then
|
|
926
|
-
runs outside brindle.
|
|
927
|
-
|
|
928
|
-
Never lifted: your own, the repo's, a profile's or your org's denies, git force
|
|
929
|
-
flags, and reads of `~/.ssh`, `~/.aws`, `~/.gnupg` or the daemon's token.
|
|
930
|
-
Antigravity and OpenCode workers get no grants: agy ignores a hook's allow, and
|
|
931
|
-
OpenCode's plugin has no hold.
|
|
932
|
-
|
|
933
|
-
In a Team org, only the org policy's `permission_grants` block decides what may
|
|
934
|
-
be granted. It is read again on every request:
|
|
910
|
+
**Saved actions.** The app's Inbox groups pending asks by kind and general
|
|
911
|
+
form (a push by its destination, a file by its top folder, a command by its
|
|
912
|
+
first two words, an MCP tool or its server). One decision answers the group:
|
|
913
|
+
once, for the session, for a time, until revoked, deny, or always deny. Anything
|
|
914
|
+
kept is a saved action, listed and editable under Settings → Permissions. A
|
|
915
|
+
saved deny stops every ask it covers. A saved allow settles an ask only within
|
|
916
|
+
the limits of the ask rule that asked (its scope and how long approvals may
|
|
917
|
+
last), never past a deny rule, and never once it has expired. Every use reads
|
|
918
|
+
the current rules again.
|
|
919
|
+
|
|
920
|
+
Saved actions and the grouped Inbox are in the app only for now. From the
|
|
921
|
+
CLI, saved actions still apply to every worker, but you can't list, edit or
|
|
922
|
+
delete one (`brindle permissions reset` removes them all, with your own and
|
|
923
|
+
learned rules), and without the app a held request falls back to the worker
|
|
924
|
+
CLI's own prompt in its pane, one exact request at a time. CLI commands for
|
|
925
|
+
both are tracked in
|
|
926
|
+
[#285](https://github.com/PawDelta/brindle/issues/285).
|
|
927
|
+
|
|
928
|
+
In a Team org, the org policy's `permission_grants` block bounds what a saved
|
|
929
|
+
allow may do. It is read again on every request:
|
|
935
930
|
|
|
936
931
|
```json
|
|
937
|
-
"permission_grants": {"allow": true, "kinds": ["bash", "fetch"], "
|
|
938
|
-
"
|
|
939
|
-
"deny": ["bash prefix terraform apply"]}
|
|
932
|
+
"permission_grants": {"allow": true, "kinds": ["bash", "fetch"], "max_minutes": 30,
|
|
933
|
+
"allow_persistent": true, "lifetimes": ["session", "time", "forever"],
|
|
934
|
+
"scopes": ["branch", "remote"], "deny": ["bash prefix terraform apply"]}
|
|
940
935
|
```
|
|
941
936
|
|
|
942
937
|
- `deny` entries are enforced for every provider and can't be lifted.
|
|
943
|
-
-
|
|
944
|
-
- A policy without the block,
|
|
945
|
-
-
|
|
946
|
-
- The org backend that serves this block isn't part of this repository. Until it serves one, Team orgs get no grants. It is enforced from the cached policy, or in air-gap mode from `.brindle/policy.json`.
|
|
938
|
+
- A saved allow applies only for the listed `kinds`, `lifetimes` and `scopes`, with timed ones capped at `max_minutes`; one that lasts until revoked also needs `allow_persistent`.
|
|
939
|
+
- A policy without the block, one that can't be read, or a paused or shut-down member: no saved allow applies.
|
|
940
|
+
- Org admins edit the block in Settings → Organization approvals. It is enforced from the cached policy, or in air-gap mode from `.brindle/policy.json`.
|
|
947
941
|
|
|
948
942
|
**Codex.** Codex runs a hook only once it's trusted, so with
|
|
949
943
|
`permission_policy` on, brindle trusts its own hook the first time a Codex worker
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "brindle"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.1"
|
|
4
4
|
description = "Run coding agents in parallel, each on its own git branch, with a supervisor that delegates, reviews, and merges"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -36,7 +36,7 @@ Changelog = "https://pawdelta.com/brindle/changelog"
|
|
|
36
36
|
Support = "https://pawdelta.com/brindle/docs/faq"
|
|
37
37
|
|
|
38
38
|
[project.scripts]
|
|
39
|
-
brindle = "brindle.
|
|
39
|
+
brindle = "brindle.entry:main"
|
|
40
40
|
|
|
41
41
|
# brindle Pro and Team (src/brindle/pro): inert without a verified entitlement.
|
|
42
42
|
[project.entry-points."brindle.account"]
|