briar-cli 1.1.1__py3-none-any.whl

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.
Files changed (179) hide show
  1. briar/__init__.py +8 -0
  2. briar/__main__.py +11 -0
  3. briar/_registry.py +36 -0
  4. briar/agent/__init__.py +16 -0
  5. briar/agent/_llm.py +90 -0
  6. briar/agent/_llms/__init__.py +40 -0
  7. briar/agent/_llms/anthropic_llm.py +185 -0
  8. briar/agent/_llms/bedrock.py +154 -0
  9. briar/agent/_llms/gemini.py +152 -0
  10. briar/agent/_llms/openai_llm.py +129 -0
  11. briar/agent/runner.py +364 -0
  12. briar/agent/tools.py +355 -0
  13. briar/auth/__init__.py +42 -0
  14. briar/auth/_acquirer.py +121 -0
  15. briar/auth/_acquirers/__init__.py +62 -0
  16. briar/auth/_acquirers/aws_sso.py +185 -0
  17. briar/auth/_acquirers/aws_static.py +54 -0
  18. briar/auth/_acquirers/bitbucket.py +60 -0
  19. briar/auth/_acquirers/github_device.py +129 -0
  20. briar/auth/_acquirers/github_pat.py +44 -0
  21. briar/auth/_acquirers/infisical.py +80 -0
  22. briar/auth/_acquirers/jira_session.py +102 -0
  23. briar/auth/_acquirers/jira_token.py +61 -0
  24. briar/auth/_acquirers/linear.py +46 -0
  25. briar/auth/_prompt.py +155 -0
  26. briar/cli.py +149 -0
  27. briar/commands/__init__.py +48 -0
  28. briar/commands/agent.py +692 -0
  29. briar/commands/auth.py +281 -0
  30. briar/commands/base.py +46 -0
  31. briar/commands/context.py +143 -0
  32. briar/commands/dashboard.py +61 -0
  33. briar/commands/extract.py +79 -0
  34. briar/commands/iac.py +44 -0
  35. briar/commands/runbook.py +110 -0
  36. briar/commands/secrets.py +165 -0
  37. briar/commands/version.py +17 -0
  38. briar/credentials/__init__.py +48 -0
  39. briar/credentials/_bootstrap.py +93 -0
  40. briar/credentials/_bootstraps/__init__.py +80 -0
  41. briar/credentials/_bootstraps/infisical.py +115 -0
  42. briar/credentials/_store.py +63 -0
  43. briar/credentials/aws_secrets.py +102 -0
  44. briar/credentials/envfile.py +171 -0
  45. briar/credentials/infisical.py +183 -0
  46. briar/credentials/ssm.py +83 -0
  47. briar/credentials/vault.py +109 -0
  48. briar/dashboard/__init__.py +13 -0
  49. briar/dashboard/collectors.py +1354 -0
  50. briar/dashboard/server.py +154 -0
  51. briar/dashboard/templates/index.html +678 -0
  52. briar/decorators.py +48 -0
  53. briar/env_vars.py +92 -0
  54. briar/error_policy.py +273 -0
  55. briar/errors.py +48 -0
  56. briar/extract/__init__.py +52 -0
  57. briar/extract/_cloud.py +157 -0
  58. briar/extract/_clouds/__init__.py +39 -0
  59. briar/extract/_clouds/aws.py +190 -0
  60. briar/extract/_clouds/azure.py +152 -0
  61. briar/extract/_clouds/gcp.py +135 -0
  62. briar/extract/_gh.py +159 -0
  63. briar/extract/_provider.py +218 -0
  64. briar/extract/_providers/__init__.py +60 -0
  65. briar/extract/_providers/bitbucket.py +276 -0
  66. briar/extract/_providers/github.py +277 -0
  67. briar/extract/_tracker.py +124 -0
  68. briar/extract/_trackers/__init__.py +44 -0
  69. briar/extract/_trackers/_jira_auth.py +258 -0
  70. briar/extract/_trackers/bitbucket.py +131 -0
  71. briar/extract/_trackers/github_issues.py +139 -0
  72. briar/extract/_trackers/jira.py +191 -0
  73. briar/extract/_trackers/linear.py +172 -0
  74. briar/extract/_user_filter.py +150 -0
  75. briar/extract/active_tickets.py +71 -0
  76. briar/extract/active_work.py +87 -0
  77. briar/extract/aws_infra.py +79 -0
  78. briar/extract/aws_services/__init__.py +31 -0
  79. briar/extract/aws_services/base.py +25 -0
  80. briar/extract/aws_services/ecs.py +43 -0
  81. briar/extract/aws_services/lambda_.py +38 -0
  82. briar/extract/aws_services/logs.py +39 -0
  83. briar/extract/aws_services/rds.py +35 -0
  84. briar/extract/aws_services/sqs.py +25 -0
  85. briar/extract/base.py +290 -0
  86. briar/extract/code_hotspots.py +134 -0
  87. briar/extract/codebase_conventions.py +72 -0
  88. briar/extract/composer.py +85 -0
  89. briar/extract/github_deployments.py +106 -0
  90. briar/extract/language_detectors/__init__.py +24 -0
  91. briar/extract/language_detectors/base.py +29 -0
  92. briar/extract/language_detectors/go.py +26 -0
  93. briar/extract/language_detectors/node.py +42 -0
  94. briar/extract/language_detectors/python.py +41 -0
  95. briar/extract/pr_archaeology.py +131 -0
  96. briar/extract/pr_review_context.py +123 -0
  97. briar/extract/reviewer_profile.py +141 -0
  98. briar/extract/ticket_archaeology.py +115 -0
  99. briar/extract/ticket_context.py +95 -0
  100. briar/formatting/__init__.py +67 -0
  101. briar/formatting/base.py +25 -0
  102. briar/formatting/csv.py +34 -0
  103. briar/formatting/json.py +19 -0
  104. briar/formatting/quiet.py +29 -0
  105. briar/formatting/table.py +97 -0
  106. briar/formatting/yaml.py +35 -0
  107. briar/iac/__init__.py +18 -0
  108. briar/iac/config_file.py +114 -0
  109. briar/iac/models.py +232 -0
  110. briar/iac/reference_map.py +33 -0
  111. briar/iac/runbook/__init__.py +32 -0
  112. briar/iac/runbook/executor.py +365 -0
  113. briar/iac/runbook/models.py +156 -0
  114. briar/iac/runbook/scheduler.py +187 -0
  115. briar/iac/scaffold/__init__.py +25 -0
  116. briar/iac/scaffold/_composer.py +308 -0
  117. briar/iac/scaffold/_knowledge.py +119 -0
  118. briar/iac/scaffold/archetypes/__init__.py +26 -0
  119. briar/iac/scaffold/archetypes/base.py +85 -0
  120. briar/iac/scaffold/archetypes/engineer.py +64 -0
  121. briar/iac/scaffold/archetypes/pr_ci_fixer.py +100 -0
  122. briar/iac/scaffold/archetypes/pr_conflict_resolver.py +83 -0
  123. briar/iac/scaffold/archetypes/pr_fixer.py +62 -0
  124. briar/iac/scaffold/archetypes/triager.py +50 -0
  125. briar/iac/scaffold/base.py +19 -0
  126. briar/iac/scaffold/implementation.py +59 -0
  127. briar/iac/scaffold/pr_fixes.py +52 -0
  128. briar/iac/scaffold/rules/__init__.py +64 -0
  129. briar/iac/scaffold/rules/base.py +121 -0
  130. briar/iac/scaffold/rules/commit_as_human.md +22 -0
  131. briar/iac/scaffold/rules/minimum_correct_fix.md +20 -0
  132. briar/iac/scaffold/rules/no_force_push.md +19 -0
  133. briar/iac/scaffold/rules/no_new_pr_creation.md +16 -0
  134. briar/iac/scaffold/rules/no_workflow_file_edits.md +21 -0
  135. briar/iac/scaffold/rules/read_all_comments_first.md +20 -0
  136. briar/iac/scaffold/rules/skip_approved_green_prs.md +17 -0
  137. briar/iac/scaffold/shapes/__init__.py +38 -0
  138. briar/iac/scaffold/shapes/base.py +17 -0
  139. briar/iac/scaffold/shapes/one_shot.py +48 -0
  140. briar/iac/scaffold/shapes/plan_approve_act.py +134 -0
  141. briar/iac/scaffold/shapes/triage.py +49 -0
  142. briar/iac/scaffold/sources/__init__.py +26 -0
  143. briar/iac/scaffold/sources/aws.py +69 -0
  144. briar/iac/scaffold/sources/base.py +61 -0
  145. briar/iac/scaffold/sources/bitbucket.py +164 -0
  146. briar/iac/scaffold/sources/github.py +155 -0
  147. briar/iac/scaffold/sources/jira.py +147 -0
  148. briar/iac/scaffold/triggers/__init__.py +23 -0
  149. briar/iac/scaffold/triggers/base.py +24 -0
  150. briar/iac/scaffold/triggers/bitbucket_webhook.py +54 -0
  151. briar/iac/scaffold/triggers/github_webhook.py +52 -0
  152. briar/iac/scaffold/triggers/manual.py +16 -0
  153. briar/iac/scaffold/triggers/schedule_cron.py +37 -0
  154. briar/log_context.py +73 -0
  155. briar/logging.py +68 -0
  156. briar/messaging/__init__.py +66 -0
  157. briar/messaging/_writer.py +90 -0
  158. briar/messaging/bitbucket_pr_comment.py +93 -0
  159. briar/messaging/github_pr_comment.py +90 -0
  160. briar/messaging/jira_comment.py +63 -0
  161. briar/messaging/jira_transition.py +71 -0
  162. briar/messaging/slack_channel.py +73 -0
  163. briar/messaging/telegram_chat.py +68 -0
  164. briar/notify/__init__.py +44 -0
  165. briar/notify/_sink.py +27 -0
  166. briar/notify/email.py +59 -0
  167. briar/notify/pagerduty.py +67 -0
  168. briar/notify/slack.py +49 -0
  169. briar/notify/telegram.py +48 -0
  170. briar/pagination.py +37 -0
  171. briar/settings.py +3 -0
  172. briar/storage/__init__.py +73 -0
  173. briar/storage/base.py +137 -0
  174. briar/storage/file.py +111 -0
  175. briar/storage/postgres.py +353 -0
  176. briar_cli-1.1.1.dist-info/METADATA +1031 -0
  177. briar_cli-1.1.1.dist-info/RECORD +179 -0
  178. briar_cli-1.1.1.dist-info/WHEEL +4 -0
  179. briar_cli-1.1.1.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,1031 @@
1
+ Metadata-Version: 2.4
2
+ Name: briar-cli
3
+ Version: 1.1.1
4
+ Summary: Terminal client for the Briar agent-orchestration API.
5
+ Project-URL: Homepage, https://usebriar.com
6
+ Project-URL: Source, https://github.com/iklobato/usebriar-landing
7
+ Author: Briar
8
+ License-Expression: MIT
9
+ Keywords: agents,briar,cli,workflow
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: anthropic<1,>=0.40
22
+ Requires-Dist: atlassian-python-api<4,>=3.41
23
+ Requires-Dist: boto3<2,>=1.34
24
+ Requires-Dist: httpx<1,>=0.27
25
+ Requires-Dist: jinja2<4,>=3.1
26
+ Requires-Dist: psycopg[binary]<4,>=3.1
27
+ Requires-Dist: pydantic<3,>=2.5
28
+ Requires-Dist: pygithub<3,>=2.5
29
+ Requires-Dist: pytz
30
+ Requires-Dist: pyyaml<7,>=6.0
31
+ Requires-Dist: rich<14,>=13
32
+ Requires-Dist: schedule<2,>=1.2
33
+ Provides-Extra: all
34
+ Requires-Dist: azure-identity<2,>=1.15; extra == 'all'
35
+ Requires-Dist: azure-mgmt-appcontainers<4,>=3.0; extra == 'all'
36
+ Requires-Dist: azure-mgmt-loganalytics<14,>=12.0; extra == 'all'
37
+ Requires-Dist: azure-mgmt-rdbms<11,>=10.1; extra == 'all'
38
+ Requires-Dist: azure-mgmt-servicebus<9,>=8.2; extra == 'all'
39
+ Requires-Dist: azure-mgmt-subscription<4,>=3.1; extra == 'all'
40
+ Requires-Dist: google-api-python-client<3,>=2.100; extra == 'all'
41
+ Requires-Dist: google-auth<3,>=2.20; extra == 'all'
42
+ Requires-Dist: google-cloud-logging<4,>=3.8; extra == 'all'
43
+ Requires-Dist: google-cloud-pubsub<3,>=2.18; extra == 'all'
44
+ Requires-Dist: google-cloud-run<1,>=0.10; extra == 'all'
45
+ Requires-Dist: google-generativeai<1,>=0.7; extra == 'all'
46
+ Requires-Dist: hvac<3,>=2.0; extra == 'all'
47
+ Requires-Dist: infisicalsdk<2,>=1.0; extra == 'all'
48
+ Requires-Dist: openai<2,>=1.40; extra == 'all'
49
+ Provides-Extra: azure
50
+ Requires-Dist: azure-identity<2,>=1.15; extra == 'azure'
51
+ Requires-Dist: azure-mgmt-appcontainers<4,>=3.0; extra == 'azure'
52
+ Requires-Dist: azure-mgmt-loganalytics<14,>=12.0; extra == 'azure'
53
+ Requires-Dist: azure-mgmt-rdbms<11,>=10.1; extra == 'azure'
54
+ Requires-Dist: azure-mgmt-servicebus<9,>=8.2; extra == 'azure'
55
+ Requires-Dist: azure-mgmt-subscription<4,>=3.1; extra == 'azure'
56
+ Provides-Extra: dev
57
+ Requires-Dist: black<26,>=25; extra == 'dev'
58
+ Requires-Dist: mypy<2,>=1.13; extra == 'dev'
59
+ Provides-Extra: gcp
60
+ Requires-Dist: google-api-python-client<3,>=2.100; extra == 'gcp'
61
+ Requires-Dist: google-auth<3,>=2.20; extra == 'gcp'
62
+ Requires-Dist: google-cloud-logging<4,>=3.8; extra == 'gcp'
63
+ Requires-Dist: google-cloud-pubsub<3,>=2.18; extra == 'gcp'
64
+ Requires-Dist: google-cloud-run<1,>=0.10; extra == 'gcp'
65
+ Provides-Extra: gemini
66
+ Requires-Dist: google-generativeai<1,>=0.7; extra == 'gemini'
67
+ Provides-Extra: infisical
68
+ Requires-Dist: infisicalsdk<2,>=1.0; extra == 'infisical'
69
+ Provides-Extra: openai
70
+ Requires-Dist: openai<2,>=1.40; extra == 'openai'
71
+ Provides-Extra: test
72
+ Provides-Extra: vault
73
+ Requires-Dist: hvac<3,>=2.0; extra == 'vault'
74
+ Description-Content-Type: text/markdown
75
+
76
+ # briar — local extraction + scheduling CLI
77
+
78
+ Python CLI that mines live state from external systems (GitHub,
79
+ Bitbucket, AWS, GCP, Azure, Jira, Linear, …), schedules per-company
80
+ extraction in-process, and runs autonomous LLM-driven agents
81
+ against the resulting knowledge.
82
+
83
+ Everything runs locally — no `api.usebriar.com` service, no remote
84
+ workspace. Each command shells out to the external APIs directly
85
+ (via PyGithub, atlassian-python-api, boto3, anthropic, etc.) and
86
+ writes its output to local markdown files or a Postgres knowledge
87
+ store.
88
+
89
+ ```
90
+ briar version
91
+ briar-cli 1.1.0
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Install
97
+
98
+ ```bash
99
+ git clone git@github.com:iklobato/briar-cli.git
100
+ cd briar-cli
101
+ python3.12 -m venv .venv
102
+ source .venv/bin/activate
103
+ pip install -e .
104
+ briar version
105
+ ```
106
+
107
+ Optional pip extras — install only what you'll actually use. Each
108
+ adapter fails loudly if its SDK is missing, with the right install
109
+ command in the error message:
110
+
111
+ ```bash
112
+ pip install -e '.[openai]' # OpenAI LLM
113
+ pip install -e '.[gemini]' # Google Gemini LLM
114
+ pip install -e '.[vault]' # HashiCorp Vault credential store
115
+ pip install -e '.[gcp]' # GCP cloud provider
116
+ pip install -e '.[azure]' # Azure cloud provider
117
+ pip install -e '.[infisical]' # Infisical credential bootstrap
118
+ pip install -e '.[all]' # everything above
119
+ ```
120
+
121
+ Base install always works for: GitHub + Bitbucket extractors, AWS
122
+ infra, Jira/Linear/GitHub-Issues/Bitbucket-Issues trackers,
123
+ Anthropic LLM, AWS Bedrock LLM, all 6 message writers (jira-comment,
124
+ jira-transition, slack-channel, telegram-chat, github-pr-comment,
125
+ bitbucket-pr-comment), all 4 notification sinks, file + postgres
126
+ knowledge stores, AWS Secrets Manager / SSM credential stores.
127
+
128
+ Python 3.10+. Tested through 3.12.
129
+
130
+ ---
131
+
132
+ ## Commands
133
+
134
+ ```
135
+ briar version
136
+ briar extract — one-shot extraction
137
+ briar runbook — scheduled extraction (extract / sweep / serve)
138
+ briar agent — autonomous LLM-driven flows (prfix / implement)
139
+ briar scaffold — emit JSON config bundles for downstream tools
140
+ briar context — read/write local markdown blobs
141
+ briar dashboard — read-only HTML status page
142
+ briar auth — interactive credential acquisition (login / logout / refresh / list / status)
143
+ briar secrets — credential coverage (doctor / bootstrap)
144
+ ```
145
+
146
+ **Global flags** (apply to every subcommand):
147
+
148
+ | Flag | Purpose | Default |
149
+ |---|---|---|
150
+ | `--format {table,json,yaml,csv,quiet}` | output format | `table` |
151
+ | `--verbose` / `-v` | DEBUG-level logging | INFO |
152
+
153
+ **Global env vars:**
154
+
155
+ | Env var | Effect |
156
+ |---|---|
157
+ | `BRIAR_VERBOSE=1` | same as `--verbose` |
158
+ | `BRIAR_LIB_DEBUG=1` | also surface third-party loggers (httpx, boto3) |
159
+ | `BRIAR_DATABASE_URL` | switch the default knowledge store from `file` to `postgres` — also the final fallback DSN when no per-company override is set |
160
+ | `BRIAR_{COMPANY}_DATABASE_URL` | per-company Postgres DSN. Auto-detected when the YAML has no `knowledge.config.dsn_env`. Hyphens in company keys are uppercased + replaced with `_` (e.g. `widget-co` → `BRIAR_WIDGET_CO_DATABASE_URL`). |
161
+ | `<custom>` (when YAML sets `knowledge.config.dsn_env: MY_PG`) | reads the named env var as the DSN — fully explicit override |
162
+ | `BRIAR_NOTIFY_SINKS=telegram,slack` | scheduler failure alerts |
163
+ | `BRIAR_DEFAULT_STORE={envfile,infisical,vault,aws-secretsmanager,ssm}` | default `--store` for `briar auth login`. When set, credentials acquired interactively land here without `--store` on every invocation. |
164
+ | `BRIAR_SECRETS_FILE=/path/to/secrets.env` | override the secrets file path. Resolution order: this env var → `/etc/briar/secrets.env` (if exists) → `$XDG_CONFIG_HOME/briar/secrets.env` (or `~/.config/briar/secrets.env`) |
165
+ | `INFISICAL_CLIENT_ID` / `_SECRET` / `_PROJECT_ID` (+ optional `_ENV`, `_HOST`) | Infisical machine-identity. Drives both bootstrap (auto-hydrate at startup) AND `InfisicalStore` (`--store infisical` writes). Acquire interactively via `briar auth login infisical`. |
166
+ | `JIRA_{COMPANY}_AUTH_KIND={token,session}` | force a Jira auth strategy. Default = auto-detect (session wins when a session-token env var is set) |
167
+ | `JIRA_{COMPANY}_EMAIL` + `JIRA_{COMPANY}_TOKEN` | token-auth credentials (Atlassian-recommended) |
168
+ | `JIRA_{COMPANY}_SESSION_TOKEN` / `JIRA_{COMPANY}_TENANT_SESSION_TOKEN` | session-auth credentials (browser-extracted cookies). Either one alone is sufficient. |
169
+ | `JIRA_{COMPANY}_XSRF_TOKEN` / `JIRA_{COMPANY}_USER_AGENT` | optional session-auth extras |
170
+
171
+ ---
172
+
173
+ ## `briar version`
174
+
175
+ Prints client version. Takes no arguments.
176
+
177
+ ```bash
178
+ briar version
179
+ # briar-cli 1.1.0
180
+ ```
181
+
182
+ ---
183
+
184
+ ## `briar extract` — one-shot extraction
185
+
186
+ Run one or more extractors against external sources and write the
187
+ result to a knowledge blob.
188
+
189
+ ```
190
+ briar extract --company <name> [--include <extractor>] ...
191
+ [--storage {file,postgres}] [--root <dir>]
192
+ [--provider {github,bitbucket}]
193
+ [--tracker {jira,github-issues,bitbucket-issues,linear}]
194
+ [--cloud {aws,gcp,azure}]
195
+ [extractor-specific flags]
196
+ ```
197
+
198
+ **Required:**
199
+ - `--company` — drives the markdown title + the blob name
200
+
201
+ **Pick which extractors to run** with `--include` (repeatable; default = all available):
202
+
203
+ | Extractor | What it mines | Backed by |
204
+ |---|---|---|
205
+ | `pr-archaeology` | merged-PR patterns, top reviewers | repo |
206
+ | `active-work` | open PRs across configured repos | repo |
207
+ | `github-deployments` | environments, deployments, CI runs | repo |
208
+ | `codebase-conventions` | language, test runner, linter, migration tool | repo |
209
+ | `reviewer-profile` | per-reviewer comment cadence + sample asks | repo |
210
+ | `code-hotspots` | files that change together (co-change clusters) | repo |
211
+ | `active-tickets` | open tickets per project | tracker |
212
+ | `ticket-archaeology` | closed-ticket patterns, top assignees | tracker |
213
+ | `aws-infra` | cloud resources (compute, databases, queues, logs) | cloud |
214
+
215
+ **Extractor-specific flags** (only relevant when the matching `--include` is set):
216
+
217
+ | Flag | Used by | Notes |
218
+ |---|---|---|
219
+ | `--pr-repo <slug>` | `pr-archaeology` | repeatable; `owner/repo` |
220
+ | `--pr-max <N>` | `pr-archaeology` | default 100 |
221
+ | `--pr-authors-allow` / `--pr-authors-block` | `pr-archaeology` | allow ∩ ¬block |
222
+ | `--pr-assignees-allow` / `--pr-assignees-block` | `pr-archaeology` | |
223
+ | `--active-repo <slug>` | `active-work` | repeatable |
224
+ | `--active-authors-allow` / `--active-authors-block` | `active-work` | filter open PRs |
225
+ | `--deploy-repo <slug>` | `github-deployments` | repeatable |
226
+ | `--conventions-repo <slug>` | `codebase-conventions` | repeatable |
227
+ | `--reviewer-repo <slug>` | `reviewer-profile` | repeatable |
228
+ | `--reviewer-pr-sample <N>` | `reviewer-profile` | default 20 |
229
+ | `--reviewer-top-n <N>` | `reviewer-profile` | default 5 |
230
+ | `--hotspots-repo <slug>` | `code-hotspots` | repeatable |
231
+ | `--hotspots-since-days <N>` | `code-hotspots` | default 30 |
232
+ | `--hotspots-max-commits <N>` | `code-hotspots` | default 100 |
233
+ | `--hotspots-top-n <N>` | `code-hotspots` | default 10 |
234
+ | `--ticket-project <key>` | `active-tickets` | repeatable; Jira project / Linear team key / `owner/repo` for GH+BB Issues |
235
+ | `--ticket-archaeology-project <key>` | `ticket-archaeology` | repeatable |
236
+ | `--ticket-max <N>` | `ticket-archaeology` | default 100 |
237
+ | `--aws-extract-region <region>` | `aws-infra` | default `us-east-1` |
238
+ | `--aws-extract-service <svc>` | `aws-infra` | one of `ecs lambda logs rds sqs`; repeatable |
239
+ | `--aws-extract-profile <name>` | `aws-infra` | local AWS profile; falls back to per-company env vars |
240
+
241
+ **Storage flags** (apply to every extraction):
242
+
243
+ | Flag | Purpose |
244
+ |---|---|
245
+ | `--storage {file,postgres}` | default `file` |
246
+ | `--blob-name <name>` | default `knowledge:<company>` |
247
+ | `--root <dir>` | file-store root (default `./knowledge`) |
248
+ | `--out-json <path>` | parallel JSON output (empty = skip) |
249
+
250
+ **Examples:**
251
+
252
+ ```bash
253
+ # Just PR archaeology against one GitHub repo
254
+ briar extract --company acme \
255
+ --include pr-archaeology \
256
+ --pr-repo acme-co/acme-app --pr-max 50
257
+
258
+ # PRs + AWS infra in one shot, filter to team members only
259
+ briar extract --company acme \
260
+ --include pr-archaeology --include aws-infra \
261
+ --pr-repo acme-co/acme-app \
262
+ --pr-authors-allow alice --pr-authors-allow bob \
263
+ --aws-extract-region us-east-1 \
264
+ --aws-extract-service ecs --aws-extract-service rds
265
+
266
+ # Bitbucket repo + Jira tickets
267
+ briar extract --company acme \
268
+ --provider bitbucket --tracker jira \
269
+ --include pr-archaeology --include active-tickets \
270
+ --pr-repo acme/api \
271
+ --ticket-project ACME
272
+
273
+ # Hotspots against a GitHub repo, 60-day window
274
+ briar extract --company acme \
275
+ --include code-hotspots \
276
+ --hotspots-repo acme-co/acme-app \
277
+ --hotspots-since-days 60
278
+
279
+ # Write to Postgres instead of files
280
+ BRIAR_DATABASE_URL=postgresql://... briar extract --company acme \
281
+ --include active-work --active-repo acme-co/acme-app \
282
+ --storage postgres
283
+ ```
284
+
285
+ ---
286
+
287
+ ## `briar runbook` — scheduled extraction
288
+
289
+ Three subcommands. All take a YAML file or a directory of YAMLs.
290
+ See [`examples/all_features.yaml`](examples/all_features.yaml) for
291
+ the comprehensive multi-company reference; [`examples/multi_company.yaml`](examples/multi_company.yaml)
292
+ is the lighter-touch tutorial.
293
+
294
+ ### `briar runbook extract <file.yaml>`
295
+
296
+ Walks a runbook YAML's `schedules:` once and writes per-company
297
+ knowledge files. Exits after one pass.
298
+
299
+ | Flag | Purpose |
300
+ |---|---|
301
+ | `--task <name>` | run only the schedule whose `task:` field matches |
302
+
303
+ ```bash
304
+ # Run everything in one runbook
305
+ briar runbook extract examples/all_features.yaml
306
+
307
+ # Run only the `prfix` task across every company in the runbook
308
+ briar runbook extract examples/all_features.yaml --task prfix
309
+ ```
310
+
311
+ ### `briar runbook sweep <directory>`
312
+
313
+ Runs `extract` for every `*.yaml` in the directory. One-shot.
314
+
315
+ ```bash
316
+ briar runbook sweep examples/
317
+ ```
318
+
319
+ ### `briar runbook serve <directory>`
320
+
321
+ Long-running scheduler. Registers every `(company, task)` from every
322
+ YAML in the directory and runs the schedule loop forever. This is
323
+ what runs persistently on the droplet.
324
+
325
+ | Flag | Purpose |
326
+ |---|---|
327
+ | `--tick <seconds>` | scheduler tick interval (default 1) |
328
+
329
+ ```bash
330
+ briar runbook serve examples/
331
+
332
+ # Tighter polling for low-cadence schedules
333
+ briar runbook serve examples/ --tick 5
334
+ ```
335
+
336
+ ---
337
+
338
+ ## `briar agent` — autonomous LLM flows
339
+
340
+ Two ops. Each clones a worktree, fetches JIT context for the specific
341
+ ticket/PR, and drives an LLM tool-use loop until completion.
342
+
343
+ ### `briar agent prfix`
344
+
345
+ Address unresolved review comments + failing CI on one PR.
346
+
347
+ | Flag | Required | Purpose |
348
+ |---|---|---|
349
+ | `--company <name>` | ✓ | matches a runbook YAML |
350
+ | `--owner <name>` | ✓ | repo owner |
351
+ | `--repo <name>` | ✓ | repo name |
352
+ | `--pr <N>` | ✓ | PR number |
353
+ | `--branch <name>` | ✓ | PR head branch |
354
+ | `--store {file,postgres}` | | knowledge store |
355
+ | `--knowledge <dir>` | | file-store root |
356
+ | `--runbook <yaml>` | | binds the `send_message` tool to the company's `messages:` block |
357
+ | `--dry-run` | | print rendered prompt + tool list, skip LLM call |
358
+ | `--model <name>` | | override Anthropic model |
359
+ | `--max-iter <N>` | | iteration ceiling |
360
+ | `--git-user-name` / `--git-user-email` | | commit identity. Per-field resolution: CLI flag > YAML `companies.<name>.git_identity.{name,email}` (when `--runbook` is set) > hardcoded `iklobato` default. |
361
+ | `--keep-worktree` | | leave `/tmp/...` after run |
362
+
363
+ ```bash
364
+ briar agent prfix \
365
+ --company acme --owner acme-co --repo acme-app \
366
+ --pr 42 --branch fix-typo \
367
+ --runbook examples/all_features.yaml
368
+
369
+ # Validate the rendered prompt without spending tokens
370
+ briar agent prfix \
371
+ --company acme --owner acme-co --repo acme-app \
372
+ --pr 42 --branch fix-typo \
373
+ --dry-run
374
+ ```
375
+
376
+ ### `briar agent implement`
377
+
378
+ Implement one ticket end-to-end: clones default branch, fetches
379
+ ticket-context, agent branches + commits + opens a draft PR.
380
+
381
+ | Flag | Required | Purpose |
382
+ |---|---|---|
383
+ | `--company <name>` | ✓ | |
384
+ | `--owner <name>` | ✓ | repo owner / Bitbucket workspace |
385
+ | `--repo <name>` | ✓ | |
386
+ | `--ticket-project <key>` | ✓ | Jira `PROJ` / Linear team / `owner/repo` for GH+BB Issues |
387
+ | `--ticket-key <key>` | ✓ | `PROJ-123` / `#42` / `ENG-7` |
388
+ | `--tracker {jira,github-issues,bitbucket-issues,linear}` | | default `jira` |
389
+ | `--provider {github,bitbucket}` | | default `github` |
390
+ | `--runbook <yaml>` | | binds `send_message` tool |
391
+ | `--dry-run` | | print rendered prompt, skip LLM call |
392
+ | `--store` / `--knowledge` / `--model` / `--max-iter` | | as above |
393
+ | `--git-user-name` / `--git-user-email` / `--keep-worktree` | | as above |
394
+
395
+ ```bash
396
+ briar agent implement \
397
+ --company acme --owner acme-co --repo acme-app \
398
+ --ticket-project ACME --ticket-key ACME-42 \
399
+ --tracker jira \
400
+ --runbook examples/all_features.yaml
401
+
402
+ # Bitbucket repo, Linear tickets
403
+ briar agent implement \
404
+ --company bitspark --owner bitspark --repo api \
405
+ --ticket-project ENG --ticket-key ENG-7 \
406
+ --provider bitbucket --tracker linear \
407
+ --runbook examples/all_features.yaml
408
+ ```
409
+
410
+ ---
411
+
412
+ ## `briar scaffold` — JSON config bundles for downstream tools
413
+
414
+ Emits a JSON bundle that a downstream orchestrator can consume. Two
415
+ templates today.
416
+
417
+ ### `briar scaffold implementation`
418
+
419
+ Issue → plan → human approval → implement / comment.
420
+
421
+ | Flag | Required | Purpose |
422
+ |---|---|---|
423
+ | `--prefix <name>` | ✓ | prepended to every resource key |
424
+ | `--source {github,bitbucket,jira,aws}` | | repeatable; selects which sources contribute |
425
+ | `--archetype <name>` | | default `engineer`; one of `engineer`, `pr-fixer`, `pr-ci-fixer`, `pr-conflict-resolver`, `triager` |
426
+ | `--shape <name>` | | default `plan-approve-act`; one of `plan-approve-act`, `one-shot`, `triage` |
427
+ | `--trigger-kind <name>` | | default `github_webhook`; one of `github_webhook`, `bitbucket_webhook`, `schedule_cron`, `manual` |
428
+ | `--owner` / `--repo` | when `--source github` | GitHub identity |
429
+ | `--bitbucket-workspace` / `--bitbucket-repo` | when `--source bitbucket` | Bitbucket identity |
430
+ | `--auth-mode {oauth,pat}` | | default `oauth` |
431
+ | `--github-secret-id` / `--bitbucket-secret-id` | with `--auth-mode pat` | |
432
+ | `--company <name>` | | splice the company's extracted knowledge into the agent's system_prompt |
433
+ | `--model <name>` / `--llm-provider-key <key>` | | LLM defaults baked into the bundle |
434
+ | `--out <path>` | | write to file (default: stdout) |
435
+
436
+ ```bash
437
+ # GitHub source, OAuth, draft PR after plan-approve flow
438
+ briar scaffold implementation \
439
+ --prefix acme-impl \
440
+ --source github \
441
+ --owner iklobato --repo lightapi
442
+
443
+ # Bitbucket source, app-password auth, hourly cron
444
+ briar scaffold implementation \
445
+ --prefix acme-impl \
446
+ --source bitbucket \
447
+ --bitbucket-workspace acme --bitbucket-repo widgets \
448
+ --auth-mode pat --bitbucket-secret-id <uuid> \
449
+ --trigger-kind schedule_cron --schedule "0 * * * *"
450
+
451
+ # Multi-source (GitHub + Jira + AWS), one-shot agent
452
+ briar scaffold implementation \
453
+ --prefix acme-hourly \
454
+ --source github --source jira --source aws \
455
+ --owner iklobato --repo lightapi \
456
+ --shape one-shot --out acme-hourly.json
457
+ ```
458
+
459
+ ### `briar scaffold pr-fixes`
460
+
461
+ PR review-comment sweep (no human gate). Same flags as `implementation`
462
+ but archetype defaults to `pr-fixer` and shape to `one-shot`.
463
+
464
+ ```bash
465
+ briar scaffold pr-fixes \
466
+ --prefix acme-prfix \
467
+ --source github \
468
+ --owner iklobato --repo lightapi \
469
+ --trigger-kind schedule_cron --schedule "0 * * * *"
470
+ ```
471
+
472
+ ---
473
+
474
+ ## `briar context` — local markdown CRUD
475
+
476
+ Read/write named blobs in the knowledge store. Same store the
477
+ extractors write to. Blob names follow `category:identifier`.
478
+
479
+ **Common flags:**
480
+
481
+ | Flag | Purpose |
482
+ |---|---|
483
+ | `--store {file,postgres}` | default `file` |
484
+ | `--root <dir>` | file-store root (default `./knowledge`) |
485
+
486
+ ### `briar context put <name>`
487
+
488
+ | Flag | Purpose |
489
+ |---|---|
490
+ | `--content <text>` | inline content; pass `-` to read from stdin |
491
+ | `--from-file <path>` | read from file |
492
+ | `--category <name>` | override the derived category prefix |
493
+
494
+ ```bash
495
+ briar context put knowledge:acme --from-file knowledge/acme.md
496
+ briar context put memory:reviewer-iklobato --content "Focuses on typing rigor"
497
+ briar context put lessons:python-typing --content - < lessons/typing.md
498
+ ```
499
+
500
+ ### `briar context get <name>`
501
+
502
+ Prints the markdown body to stdout. No flags.
503
+
504
+ ```bash
505
+ briar context get knowledge:acme
506
+ briar context get memory:reviewer-iklobato
507
+ ```
508
+
509
+ ### `briar context list`
510
+
511
+ | Flag | Purpose |
512
+ |---|---|
513
+ | `--prefix <s>` | filter to blobs whose name starts with `<s>` |
514
+
515
+ ```bash
516
+ briar context list
517
+ briar context list --prefix lessons:
518
+ ```
519
+
520
+ ### `briar context delete <name>`
521
+
522
+ | Flag | Purpose |
523
+ |---|---|
524
+ | `--yes` | skip confirmation |
525
+
526
+ ```bash
527
+ briar context delete memory:stale --yes
528
+ ```
529
+
530
+ ### `briar context categories`
531
+
532
+ Prints distinct category prefixes. No flags.
533
+
534
+ ```bash
535
+ briar context categories
536
+ ```
537
+
538
+ ---
539
+
540
+ ## `briar dashboard` — read-only HTML status page
541
+
542
+ Runs an HTTP server with the system status across 24 collector
543
+ sections. GET-only by construction.
544
+
545
+ | Flag | Default | Purpose |
546
+ |---|---|---|
547
+ | `--host <ip>` | `0.0.0.0` | bind address |
548
+ | `--port <n>` | `8080` | bind port |
549
+ | `--examples <dir>` | `./examples` | runbook YAML directory |
550
+ | `--knowledge-store {file,postgres}` | postgres if `BRIAR_DATABASE_URL` else file | |
551
+ | `--knowledge <dir>` | `./knowledge` | file-store root |
552
+ | `--log-file <path>` | `/var/log/briar/scheduler.log` | scheduler log to tail |
553
+ | `--disk-path <path>` | `/` | which mount to size-watch |
554
+ | `--repo-path <dir>` | `.` | git repo to show deploy status from |
555
+ | `--secrets-file <path>` | `/etc/briar/secrets.env` | for the secrets-name (no values) panel |
556
+ | `--du-path <dir>` | (repeatable) | extra directories to track disk usage on |
557
+ | `--once` | — | render once and exit (smoke test) |
558
+
559
+ ```bash
560
+ # Standard production invocation
561
+ briar dashboard --host 0.0.0.0 --port 8080 \
562
+ --examples ./examples --knowledge ./knowledge --repo-path .
563
+
564
+ # Postgres-backed knowledge store
565
+ BRIAR_DATABASE_URL=postgresql://... briar dashboard --host 127.0.0.1
566
+
567
+ # Smoke test — render the HTML once and exit
568
+ briar dashboard --once > /tmp/dashboard.html
569
+ ```
570
+
571
+ ---
572
+
573
+ ## `briar auth` — interactive credential acquisition
574
+
575
+ Five subcommands. The thing-you're-logging-into is the **positional
576
+ target** (like `gh auth login`, `vault login`, `op signin`). `--store`
577
+ controls *where the resulting credentials are persisted* and defaults
578
+ to `$BRIAR_DEFAULT_STORE` then to `envfile`.
579
+
580
+ ### Targets (registered acquirers)
581
+
582
+ | Target | Flow | Writes (per company) |
583
+ |---|---|---|
584
+ | `github-pat` | Paste a Personal Access Token | `GITHUB_TOKEN` |
585
+ | `github-device` | OAuth device flow (needs `BRIAR_GITHUB_CLIENT_ID`) | `GITHUB_TOKEN` |
586
+ | `bitbucket-app-password` | Paste workspace + username + app password | `BITBUCKET_{c}_WORKSPACE` / `_USERNAME` / `_APP_PASSWORD` |
587
+ | `aws-static` | Paste static IAM access key | `AWS_{c}_ACCESS_KEY_ID` / `_SECRET_ACCESS_KEY` / `_REGION` |
588
+ | `aws-sso` | IAM Identity Center OIDC device-code flow → STS vend | `AWS_{c}_*` (+ records expiry) |
589
+ | `jira-token` | Paste API token | `JIRA_{c}_URL` / `_EMAIL` / `_TOKEN` / `_AUTH_KIND=token` |
590
+ | `jira-session` | DevTools cookie extraction walkthrough | `JIRA_{c}_URL` / `_TENANT_SESSION_TOKEN` / `_AUTH_KIND=session` |
591
+ | `linear-api-key` | Paste personal API key | `LINEAR_{c}_TOKEN` |
592
+ | `infisical` | Bootstrap — paste machine-identity creds. Always persists to envfile regardless of `--store`. | `INFISICAL_CLIENT_ID` / `_CLIENT_SECRET` / `_PROJECT_ID` / `_ENV` / `_HOST` |
593
+
594
+ ### Stores (registered persistence backends)
595
+
596
+ | Store | Notes |
597
+ |---|---|
598
+ | `envfile` | Resolves to `$BRIAR_SECRETS_FILE` → `/etc/briar/secrets.env` (if exists) → `~/.config/briar/secrets.env`. Atomic replace-in-place. |
599
+ | `infisical` | Universal-auth machine identity (configure via `briar auth login infisical` first) |
600
+ | `vault` | HashiCorp Vault KV v2 (needs `VAULT_ADDR` + `VAULT_TOKEN`) |
601
+ | `aws-secretsmanager` | One secret per name under `briar/` prefix |
602
+ | `ssm` | SSM Parameter Store, `SecureString`, `/briar/` prefix |
603
+
604
+ ### `briar auth login <target>`
605
+
606
+ ```
607
+ briar auth login <target> [--company <name>] [--store <kind>]
608
+ ```
609
+
610
+ | Flag | Purpose |
611
+ |---|---|
612
+ | `target` (positional, required) | What to log into — one of the targets above |
613
+ | `--company <name>` | Per-company namespace (required for vendor targets; ignored for `infisical`) |
614
+ | `--store <kind>` | Destination. Default = `$BRIAR_DEFAULT_STORE` or `envfile`. **Ignored** when target is a bootstrap flow (`infisical`) — those always land in envfile, with a warning if you passed something else. |
615
+
616
+ ```bash
617
+ # Bootstrap a password manager (one-time, per laptop)
618
+ briar auth login infisical
619
+ briar auth login vault # (when VaultLoginFlow lands — placeholder for now)
620
+
621
+ # Vendor credentials → land in envfile
622
+ briar auth login github-pat --company acme
623
+ briar auth login aws-sso --company acme
624
+
625
+ # Vendor credentials → land in Infisical
626
+ briar auth login github-pat --company acme --store infisical
627
+ briar auth login aws-sso --company acme --store infisical
628
+
629
+ # Pick a default store once, never re-type --store
630
+ export BRIAR_DEFAULT_STORE=infisical
631
+ briar auth login jira-session --company acme
632
+ ```
633
+
634
+ ### `briar auth logout <target>`
635
+
636
+ Removes every env-var name the target would write. Confirms unless `--yes`.
637
+
638
+ ```bash
639
+ briar auth logout aws-sso --company acme --yes
640
+ briar auth logout infisical # removes the machine identity (forgets the connection)
641
+ ```
642
+
643
+ ### `briar auth refresh <target>`
644
+
645
+ Renews short-lived bundles without re-prompting. Paste-based targets (PATs, app passwords, Jira API tokens, Jira session cookies, Infisical machine identity) raise `CredentialExpired` → re-run `login`.
646
+
647
+ ```bash
648
+ briar auth refresh aws-sso --company acme # vends fresh STS creds from cached SSO token
649
+ ```
650
+
651
+ ### `briar auth list [--store <kind>] [--company <name>]`
652
+
653
+ Enumerates the credential names held in the chosen store. Names only — never values.
654
+
655
+ ```bash
656
+ briar auth list --store envfile
657
+ briar auth list --store infisical --company acme
658
+ ```
659
+
660
+ ### `briar auth status <target>`
661
+
662
+ Per-key `ok` / `MISS` report for the bundle a target writes. Exits non-zero on any miss.
663
+
664
+ ```bash
665
+ briar auth status aws-sso --company acme
666
+ briar auth status jira-session --company acme --store infisical
667
+ ```
668
+
669
+ ---
670
+
671
+ ## `briar secrets` — credential coverage + remote-vault hydrate
672
+
673
+ Two subcommands.
674
+
675
+ ### `briar secrets doctor`
676
+
677
+ Walks every runbook YAML's `schedules:` and `messages:` blocks. For
678
+ each `(company, extractor, provider)` and `(company, messages,
679
+ writer)` tuple, queries the provider/writer's `required_env_vars(company)`
680
+ classmethod and reports `ok` / `X MISSING:` per row against the
681
+ chosen credential store. Values are never printed.
682
+
683
+ | Flag | Default | Purpose |
684
+ |---|---|---|
685
+ | `--examples <dir>` | `./examples` | runbook YAML directory |
686
+ | `--store {envfile,aws-secretsmanager,ssm,vault}` | `envfile` | which credential backend to audit against |
687
+
688
+ ```bash
689
+ # Default: audit env vars
690
+ briar secrets doctor --examples examples/
691
+
692
+ # Audit against AWS Secrets Manager (paths under /briar/<NAME>)
693
+ briar secrets doctor --store aws-secretsmanager
694
+
695
+ # Audit a single YAML directory
696
+ briar secrets doctor --examples examples/
697
+ ```
698
+
699
+ Exits non-zero when any row is missing.
700
+
701
+ ### `briar secrets bootstrap`
702
+
703
+ Fetches secrets from a remote vault and writes them to `os.environ`.
704
+ Normally runs automatically at CLI startup via `auto_bootstrap()`;
705
+ this subcommand is for testing.
706
+
707
+ | Flag | Purpose |
708
+ |---|---|
709
+ | `--kind {infisical}` | force a backend; default is auto-detect via `is_available()` |
710
+ | `--dry-run` | run the fetch but DON'T write to env; prints keys that would be set |
711
+
712
+ ```bash
713
+ # Auto-detect (runs Infisical if INFISICAL_CLIENT_ID is set)
714
+ briar secrets bootstrap
715
+
716
+ # Dry-run — see what would be hydrated without leaking values
717
+ briar secrets bootstrap --dry-run
718
+
719
+ # Force one backend
720
+ briar secrets bootstrap --kind infisical
721
+ ```
722
+
723
+ Operator-supplied env vars take precedence over the vault — already-set
724
+ keys are preserved (reported as `skipped`).
725
+
726
+ ---
727
+
728
+ ## How the pieces fit together
729
+
730
+ Three command families, three concerns. Each diagram shows what a
731
+ command reads, what it invokes, and what comes out — so you can
732
+ predict the blast radius of a change.
733
+
734
+ ### `briar runbook serve <dir>` — the long-running scheduler
735
+
736
+ ```
737
+ ┌──────────────────────────────────────────┐
738
+ │ briar runbook serve companies/ --tick 5 │
739
+ └─────────────────────┬────────────────────┘
740
+
741
+ reads at startup │ reads at every fire
742
+ ┌──────────────────────┐ │ ┌────────────────────────┐
743
+ │ companies/*.yaml │ │ │ /etc/briar/secrets.env │
744
+ │ (CompanyEntry + │◄──────┴──────►│ per-fire env vars │
745
+ │ ScheduleEntry) │ │ (GITHUB_TOKEN, │
746
+ └──────────────────────┘ │ JIRA_*, AWS_*, ...) │
747
+ └────────────────────────┘
748
+
749
+
750
+ ┌─────────────────────────┐
751
+ │ scheduler loop (tick) │
752
+ │ • registers cron-ish │
753
+ │ jobs per ScheduleEntry│
754
+ │ • fires due jobs │
755
+ └────────────┬────────────┘
756
+
757
+
758
+ ┌─────────────────────────┐
759
+ │ RunbookExecutor.extract │
760
+ └────────────┬────────────┘
761
+
762
+ ┌─────────────────────┼─────────────────────┐
763
+ ▼ ▼ ▼
764
+ ┌────────────────┐ ┌────────────────────┐ ┌──────────────────┐
765
+ │ EXTRACTORS[..] │ │ KnowledgeComposer │ │ make_store(...) │
766
+ │ for each │──▶ .markdown(...) │──▶ .put_if_changed │
767
+ │ ExtractEntry │ │ assembles sections │ │ (md5 compare- │
768
+ │ in schedule │ │ into one blob │ │ and-set) │
769
+ └───────┬────────┘ └────────────────────┘ └────────┬─────────┘
770
+ │ │
771
+ ▼ ▼
772
+ ┌────────────────┐ ┌──────────────────┐
773
+ │ provider_class │ │ KnowledgeStore │
774
+ │ _for(args) │ │ • StoreFile │
775
+ │ ┌────────────┐│ │ • StorePostgres │
776
+ │ │ Repository ││ └──────────────────┘
777
+ │ │ Tracker ││ │
778
+ │ │ Cloud ││ ▼
779
+ │ └────────────┘│ DO managed PG / files
780
+ └────────────────┘ ./knowledge/*.md
781
+ ```
782
+
783
+ A change in `companies/*.yaml` is picked up on the **next** schedule
784
+ fire because the executor re-loads the YAML on every iteration. Code
785
+ changes need a scheduler restart (the `briar` Python process caches
786
+ imported modules).
787
+
788
+ ### `briar runbook extract <file.yaml>` — one-shot
789
+
790
+ ```
791
+ briar runbook extract companies/acme.yaml [--task tickets]
792
+
793
+
794
+ Same executor path as `serve`,
795
+ but runs once and exits.
796
+ --task filters which ScheduleEntry to fire.
797
+ ```
798
+
799
+ Useful for manual smoke tests against a specific task (e.g.
800
+ verifying Jira session auth before letting the scheduler run for
801
+ 24h on its own cadence).
802
+
803
+ ### `briar agent prfix` / `briar agent implement` — autonomous LLM
804
+
805
+ ```
806
+ ┌─────────────────────────────────────────────────────┐
807
+ │ briar agent prfix --company acme │
808
+ │ --owner acme-co --repo acme-app │
809
+ │ --pr 42 --branch feature/x │
810
+ │ --runbook companies/acme.yaml │
811
+ └────────────────────────┬────────────────────────────┘
812
+
813
+ ┌───────────────────────┼────────────────────────┐
814
+ ▼ ▼ ▼
815
+ ┌──────────┐ ┌────────────┐ ┌─────────────────┐
816
+ │ secrets │ │ companies/ │ │ KnowledgeStore │
817
+ │ .env │ │ acme.yaml│ │ .get("knowledge:│
818
+ │ • GITHUB │ │ • messages │ │ acme") │
819
+ │ • JIRA_* │ │ • git_id │ │ (previously │
820
+ │ • CLAUDE │ └─────┬──────┘ │ written by │
821
+ └────┬─────┘ │ │ serve) │
822
+ │ ▼ └────────┬────────┘
823
+ │ ┌─────────────────┐ │
824
+ │ │_resolve_git_id │ │
825
+ │ │ (CLI > YAML > │ │
826
+ │ │ default) │ │
827
+ │ └────────┬────────┘ │
828
+ │ │ │
829
+ ▼ ▼ ▼
830
+ ┌──────────────────────────────────────────────────────────┐
831
+ │ RepoCloner.clone(branch) → /tmp/<worktree> │
832
+ │ • sets user.name + user.email on the clone │
833
+ └────────────────────────────┬─────────────────────────────┘
834
+
835
+
836
+ ┌──────────────────────────────────────────────────────────┐
837
+ │ FetchPrContext (JIT extractor: reads PR + review thread) │
838
+ └────────────────────────────┬─────────────────────────────┘
839
+
840
+
841
+ ┌──────────────────────────────────────────────────────────┐
842
+ │ AgentRunner (Anthropic API + tool-use loop) │
843
+ │ tools available: │
844
+ │ • bash, read_file, write_file, edit_file │
845
+ │ • send_message ←──┐ │
846
+ └────────────┬──────────│──────────────────────────────────┘
847
+ │ │
848
+ │ │ resolved via messages: block:
849
+ │ │ handle → MessageWriter
850
+ │ │ ├── jira-comment / jira-transition
851
+ │ │ │ (uses JiraAuthStrategy)
852
+ │ │ ├── github-pr-comment
853
+ │ │ ├── bitbucket-pr-comment
854
+ │ │ ├── slack-channel
855
+ │ │ └── telegram-chat
856
+ │ │
857
+
858
+ commits + push via the same RepositoryProvider
859
+ used in the scheduler — closes the loop.
860
+ ```
861
+
862
+ `briar agent implement` is the same shape, replacing
863
+ `FetchPrContext` with `FetchTicketContext` (which reads from the
864
+ TrackerProvider for the company's chosen tracker).
865
+
866
+ ### DSN resolution — `knowledge.store: postgres`
867
+
868
+ ```
869
+ KnowledgeBinding (from YAML)
870
+
871
+ │ knowledge:
872
+ │ store: postgres
873
+ │ config:
874
+ │ dsn_env: BRIAR_KB_DATABASE_URL ← explicit
875
+
876
+
877
+ StoreBinding(company="acme", config={...})
878
+
879
+
880
+ StorePostgres.from_binding(binding):
881
+ ┌──────────────────────────────────────────────────────────┐
882
+ │ 1. binding.config["dsn_env"] → ${BRIAR_KB_DATABASE_URL}
883
+ │ 2. BRIAR_{COMPANY}_DATABASE_URL → ${BRIAR_ACME_DATABASE_URL}
884
+ │ 3. BRIAR_DATABASE_URL → ${BRIAR_DATABASE_URL}
885
+ │ 4. CliError naming all 3 keys tried, in order
886
+ └──────────────────────────────────────────────────────────┘
887
+
888
+
889
+ returns psycopg-backed StorePostgres instance
890
+ ```
891
+
892
+ The first non-empty env var wins. Every downstream caller
893
+ (`scheduler`, `briar context`, `briar agent`'s `KnowledgeStore.get`)
894
+ goes through the same factory — no parallel resolution paths.
895
+
896
+ ### Jira auth strategy chain
897
+
898
+ ```
899
+ JiraTracker(company="acme")
900
+
901
+
902
+ JiraAuthRegistry.autodetect(company="acme"):
903
+ ┌──────────────────────────────────────────────────────────┐
904
+ │ 1. JIRA_{COMPANY}_AUTH_KIND env (explicit override) │
905
+ │ "token" → JiraTokenAuth │
906
+ │ "session" → JiraSessionAuth │
907
+ │ 2. JIRA_{COMPANY}_SESSION_TOKEN OR _TENANT_SESSION_TOKEN │
908
+ │ set → JiraSessionAuth │
909
+ │ 3. fallback → JiraTokenAuth │
910
+ └──────────────────────────────────────────────────────────┘
911
+
912
+
913
+ strategy.configure(company, base_url)
914
+
915
+ ├── token → {username, password} ── HTTP Basic
916
+
917
+ └── session → {session: requests.Session(
918
+ cookies={cloud.session.token, tenant.session.token,
919
+ atlassian.xsrf.token},
920
+ headers={Origin, Referer, User-Agent,
921
+ sec-ch-ua-*, sec-fetch-*,
922
+ X-Atlassian-Token: no-check})}
923
+ ── browser-mimicking
924
+
925
+
926
+ atlassian.Jira(url=..., cloud=True, **kwargs)
927
+ ```
928
+
929
+ The same `JiraTracker` is used by both the scheduler's
930
+ `active-tickets` / `ticket-archaeology` extractors AND the agent's
931
+ `jira-comment` / `jira-transition` message writers — so a working
932
+ session auth for one path is a working session auth for the other.
933
+
934
+ ### `briar auth login <target>` — acquisition + persistence
935
+
936
+ ```
937
+ briar auth login <target> [--company X] [--store Y]
938
+
939
+ positional target │ --store decides persistence
940
+ resolves to │ IF the target's policy is EXTERNAL
941
+ ▼ │ (forced to envfile if BOOTSTRAP_LOCAL)
942
+ ┌─────────────────┐ │
943
+ │ AcquirerRegistry│ │
944
+ │ .make(target) │ │
945
+ └────────┬────────┘ │
946
+ │ │
947
+ ▼ │
948
+ ┌─────────────────┐ │
949
+ │ acquirer.acquire│ │
950
+ │ (company, │ │
951
+ │ prompt) │ │
952
+ └────────┬────────┘ │
953
+ │ │
954
+ ▼ │
955
+ Credentials │
956
+ (provider_kind, │
957
+ entries dict, │
958
+ expires_at) │
959
+ │ │
960
+ ▼ │
961
+ ┌───────────────────┐ │
962
+ │ _effective_store │◄────┘
963
+ │ honours policy: │
964
+ │ EXTERNAL → as-is │
965
+ │ BOOTSTRAP_LOCAL │
966
+ │ → "envfile" │
967
+ └─────────┬─────────┘
968
+
969
+
970
+ ┌──────────────────────┐
971
+ │ CredentialStore │
972
+ │ .write(name, value) │
973
+ │ for each entry │
974
+ │ │
975
+ │ Backends: │
976
+ │ • EnvFileStore │
977
+ │ • InfisicalStore │
978
+ │ • VaultStore │
979
+ │ • AwsSecretsMgr │
980
+ │ • SsmParameterStore │
981
+ └──────────────────────┘
982
+ ```
983
+
984
+ The target's `destination_policy` ClassVar splits two flavours:
985
+ - **EXTERNAL** (default) — vendor credentials (GitHub, AWS, Jira,
986
+ Linear, Bitbucket). The operator picks `--store` freely.
987
+ - **BOOTSTRAP_LOCAL** — the credentials *describe how to reach a
988
+ store* (Infisical machine identity; future `VaultLoginFlow`).
989
+ Must persist to envfile or the bootstrap is unrecoverable
990
+ (chicken-and-egg). The CLI logs a warning if `--store` is ignored.
991
+
992
+ Adding a new acquirer = one class + one registry entry. Adding a
993
+ new store = one class + one registry entry. Adding a new
994
+ destination policy (rare — e.g. "must persist to keychain") = one
995
+ enum value + one branch in `_effective_store_kind`.
996
+
997
+ ### What invalidates what
998
+
999
+ | You changed... | Restart needed | Effect |
1000
+ |---|---|---|
1001
+ | `companies/*.yaml` | no (next fire) | scheduler re-reads on every tick |
1002
+ | `/etc/briar/secrets.env` | yes | scheduler holds env in process memory |
1003
+ | `src/briar/` (editable install) | yes | imported modules are cached |
1004
+ | Postgres `briar_knowledge` table | no | scheduler reads fresh on each fire |
1005
+ | Jira session-token cookie | no — but log it | scheduler reads from env at startup; restart picks up rotation |
1006
+
1007
+ ---
1008
+
1009
+ ## Examples + further reading
1010
+
1011
+ - `companies/` (gitignored — keep your real runbooks here so they
1012
+ don't leak into the public repo). Recommended pattern: one YAML
1013
+ per company, all with `knowledge.config.dsn_env: BRIAR_KB_DATABASE_URL`
1014
+ so they share a managed-Postgres knowledge store with row-level
1015
+ partitioning by the `company` column.
1016
+ - [`examples/all_features.yaml`](examples/all_features.yaml) — every
1017
+ abstraction × provider × writer combination across 4 companies.
1018
+ Schema reference for `knowledge.config`, `messages:`, `git_identity:`,
1019
+ and the Jira auth-strategy selector.
1020
+ - [`examples/multi_company.yaml`](examples/multi_company.yaml) +
1021
+ [`.env.example`](examples/multi_company.env.example) — 3-company
1022
+ tutorial without the `messages:` block
1023
+ - [`examples/owlid.yaml`](examples/owlid.yaml) — real deployment
1024
+ (Bitbucket workspace token + AWS instance role)
1025
+ - [`IMPLEMENTATION_PLAN.md`](IMPLEMENTATION_PLAN.md) — per-provider
1026
+ credential acquisition guide (incl. Jira API token AND
1027
+ browser-session-cookie paths)
1028
+ - [`DEPLOY_EC2.md`](DEPLOY_EC2.md) — systemd deployment recipe
1029
+ - [`ARCHITECTURE.md`](ARCHITECTURE.md) +
1030
+ [`ARCHITECTURE_DEEP.md`](ARCHITECTURE_DEEP.md) — abstraction
1031
+ inventory + SOLID audit