segreant 0.1.0 → 0.2.0

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 (142) hide show
  1. package/LICENSING.md +5 -3
  2. package/README.md +57 -19
  3. package/bin/segreant-statusline.mjs +20 -0
  4. package/bin/segreant.mjs +19 -8
  5. package/dist/alerts/detect.js +13 -0
  6. package/dist/billing/epistemic.js +4 -0
  7. package/dist/billing/importer.js +29 -10
  8. package/dist/billing/reconcile.js +122 -32
  9. package/dist/billing/scope.js +7 -0
  10. package/dist/budget/guard.js +33 -4
  11. package/dist/cli/allocCmd.js +73 -4
  12. package/dist/cli/askModelPrices.js +59 -0
  13. package/dist/cli/backupCmd.js +2 -1
  14. package/dist/cli/basisLines.js +45 -0
  15. package/dist/cli/billingCmd.js +68 -9
  16. package/dist/cli/capitalCmd.js +2 -1
  17. package/dist/cli/connectCmd.js +50 -9
  18. package/dist/cli/egressCmd.js +15 -3
  19. package/dist/cli/evidenceCmd.js +6 -3
  20. package/dist/cli/flags.js +68 -0
  21. package/dist/cli/homeCmd.js +117 -0
  22. package/dist/cli/importCmd.js +210 -54
  23. package/dist/cli/launchCmd.js +2 -1
  24. package/dist/cli/opsCmd.js +49 -2
  25. package/dist/cli/planCmd.js +181 -0
  26. package/dist/cli/pricingDeclareCmd.js +178 -0
  27. package/dist/cli/quotaCmd.js +190 -0
  28. package/dist/cli/runCmd.js +203 -51
  29. package/dist/cli/showCmd.js +37 -11
  30. package/dist/cli/teamCmd.js +5 -5
  31. package/dist/cli/ui.js +24 -8
  32. package/dist/cli/valueCmd.js +189 -14
  33. package/dist/cli.js +102 -21
  34. package/dist/config.js +95 -6
  35. package/dist/connect/antigravity.js +310 -0
  36. package/dist/connect/claudeCode.js +43 -3
  37. package/dist/connect/codex.js +38 -1
  38. package/dist/connect/importShared.js +58 -5
  39. package/dist/connect/opencode.js +37 -9
  40. package/dist/connect/protobuf.js +126 -0
  41. package/dist/connect/registry.js +46 -0
  42. package/dist/connect/repoRoot.js +112 -0
  43. package/dist/cost/basis.js +168 -0
  44. package/dist/cost/declarations.js +37 -0
  45. package/dist/cost/exactPricing.js +4 -1
  46. package/dist/cost/firstSight.js +98 -0
  47. package/dist/cost/overrides.js +230 -0
  48. package/dist/cost/pricing.js +228 -15
  49. package/dist/cost/reprice.js +130 -0
  50. package/dist/dashboard/claim-support.js +11 -8
  51. package/dist/dashboard/contracts.js +23 -3
  52. package/dist/dashboard/routes.js +980 -112
  53. package/dist/dashboard/sessions.js +345 -0
  54. package/dist/dashboard/settings.js +2 -1
  55. package/dist/dashboard/value-cache.js +105 -0
  56. package/dist/dashboard/web/app/components/claimInspector.js +6 -5
  57. package/dist/dashboard/web/app/components/drawer.js +105 -35
  58. package/dist/dashboard/web/app/components/ruleFields.js +144 -0
  59. package/dist/dashboard/web/app/components/spine.js +54 -24
  60. package/dist/dashboard/web/app/components/workflow.js +82 -0
  61. package/dist/dashboard/web/app/core/actions.js +734 -23
  62. package/dist/dashboard/web/app/core/api.js +37 -1
  63. package/dist/dashboard/web/app/core/chain.js +11 -4
  64. package/dist/dashboard/web/app/core/claimLayers.js +179 -51
  65. package/dist/dashboard/web/app/core/claimTypes.js +30 -0
  66. package/dist/dashboard/web/app/core/fmt.js +19 -2
  67. package/dist/dashboard/web/app/core/generated-contract.js +23 -3
  68. package/dist/dashboard/web/app/core/generated-payload-contract.js +1944 -465
  69. package/dist/dashboard/web/app/core/generated-types.js +1 -1
  70. package/dist/dashboard/web/app/core/griffin.js +10 -0
  71. package/dist/dashboard/web/app/core/jobs.js +12 -0
  72. package/dist/dashboard/web/app/core/period.js +35 -0
  73. package/dist/dashboard/web/app/core/periodWords.js +10 -0
  74. package/dist/dashboard/web/app/core/periods.js +32 -0
  75. package/dist/dashboard/web/app/core/pricingActions.js +264 -0
  76. package/dist/dashboard/web/app/core/privacyText.js +78 -0
  77. package/dist/dashboard/web/app/core/reconcileWords.js +63 -0
  78. package/dist/dashboard/web/app/core/registry.js +79 -46
  79. package/dist/dashboard/web/app/core/slug.js +9 -0
  80. package/dist/dashboard/web/app/core/theme.js +48 -0
  81. package/dist/dashboard/web/app/core/view.js +69 -0
  82. package/dist/dashboard/web/app/main.js +197 -15
  83. package/dist/dashboard/web/app/views/allocation.js +249 -61
  84. package/dist/dashboard/web/app/views/control.js +57 -16
  85. package/dist/dashboard/web/app/views/data.js +4 -4
  86. package/dist/dashboard/web/app/views/evidence.js +336 -87
  87. package/dist/dashboard/web/app/views/privacy.js +13 -0
  88. package/dist/dashboard/web/app/views/spend.js +30 -15
  89. package/dist/dashboard/web/app/views/statement.js +189 -0
  90. package/dist/dashboard/web/app/views/system.js +44 -4
  91. package/dist/dashboard/web/app/views/value.js +105 -59
  92. package/dist/dashboard/web/app/views/workbench.js +312 -0
  93. package/dist/dashboard/web/classic.html +16 -4
  94. package/dist/dashboard/web/index.html +1 -1
  95. package/dist/dashboard/web/styles/app.css +536 -23
  96. package/dist/demo/seed.js +153 -14
  97. package/dist/economics/ledger.js +1 -1
  98. package/dist/egress/policy.js +129 -5
  99. package/dist/export/allocationCsv.js +70 -0
  100. package/dist/export/billingCsv.js +6 -2
  101. package/dist/export/csv.js +10 -2
  102. package/dist/export/economic.js +6 -2
  103. package/dist/export/statementCsv.js +104 -0
  104. package/dist/git/correlate.js +86 -9
  105. package/dist/git/quality.js +107 -24
  106. package/dist/git/repoScope.js +207 -0
  107. package/dist/git/survivalStore.js +186 -0
  108. package/dist/guide.js +9 -4
  109. package/dist/plans/detect.js +147 -0
  110. package/dist/proxy/server.js +134 -14
  111. package/dist/proxy/usage.js +9 -4
  112. package/dist/quota/limits.js +138 -0
  113. package/dist/quota/statusline.js +68 -0
  114. package/dist/quota/view.js +122 -0
  115. package/dist/scan/knownApps.js +6 -2
  116. package/dist/scan/scan.js +9 -0
  117. package/dist/store/allocation.js +14 -0
  118. package/dist/store/db.js +259 -34
  119. package/dist/store/realization.js +78 -14
  120. package/dist/store/schema.js +59 -1
  121. package/dist/store/scopeEvidence.js +67 -0
  122. package/dist/util/pool.js +19 -0
  123. package/dist/util/time.js +7 -0
  124. package/dist/value/realization.js +321 -30
  125. package/dist/value/report.js +28 -8
  126. package/dist/value/selfReported.js +10 -9
  127. package/docs/ARCHITECTURE.md +8 -4
  128. package/docs/CAPABILITY-EVIDENCE-CONTRACT.md +33 -11
  129. package/docs/CLI-JSON-CONTRACT.md +38 -0
  130. package/docs/DATA-BOUNDARIES.md +66 -6
  131. package/docs/FAQ.md +43 -9
  132. package/docs/GETTING-STARTED.md +19 -12
  133. package/docs/GUIDE.md +81 -18
  134. package/docs/INTEGRATIONS.md +9 -9
  135. package/docs/METHODOLOGY.md +3 -2
  136. package/docs/NEUTRALITY.md +1 -1
  137. package/docs/PRIVACY.md +51 -0
  138. package/docs/README.md +1 -0
  139. package/docs/RELEASE-GATE.md +52 -7
  140. package/docs/THREAT-MODEL.md +2 -1
  141. package/package.json +3 -2
  142. package/pricing/models.json +1366 -60
@@ -49,8 +49,15 @@ card into provider billing, or alter signed/canonical evidence bytes.
49
49
  traffic, applies local soft/hard/velocity controls, and serves a local CLI and
50
50
  dashboard.
51
51
  - A Segreant-process egress boundary starts in `local_locked` mode: it permits
52
- literal loopback HTTP(S) targets only and refuses non-loopback targets before
53
- DNS. `controlled_cloud` mode permits a cloud request only when an enabled,
52
+ literal loopback HTTP(S) targets and two built-in routes, the same in every
53
+ mode: a GET of the public price list at its exact fixed URL (purpose
54
+ `pricing_refresh`, no query or fragment, rule id `segreant-builtin-price-list`),
55
+ and the user's own proxied requests to the official provider APIs
56
+ (`https://api.anthropic.com` and `https://api.openai.com`, purpose
57
+ `provider_inference`, GET or POST under `/v1/`, rule ids
58
+ `segreant-builtin-provider-*`). Both need a public DNS answer and are receipted.
59
+ Every other non-loopback target is refused before DNS in `local_locked`; in
60
+ `controlled_cloud` mode a further cloud request is permitted only when an enabled,
54
61
  exact rule matches its purpose, data class, method, HTTPS origin, and leading
55
62
  path; it pins the selected public IP for the dial, follows no redirect, and,
56
63
  after policy evaluation, writes a redacted hash-chained `preflight_allowed`
@@ -107,9 +114,16 @@ card into provider billing, or alter signed/canonical evidence bytes.
107
114
  and every other causal gate passes. Until a real protocol is registered,
108
115
  executed, and qualified, the product has no causal result to present.
109
116
  Neither path routes providers or changes budgets automatically.
110
- - The browser dashboard has no third-party assets or analytics and is intended
111
- to expose a preview before consequential local changes. The CLI remains the
112
- reference surface while GUI parity is completed.
117
+ - The browser dashboard has no third-party assets or analytics and shows a
118
+ preview before every consequential local change. Two jobs can be completed in
119
+ it end to end: Allocate (cost centres, rules, a recorded run) and Close
120
+ (declare the scope, import and adopt an export, record a reconciliation),
121
+ through local-only write routes that store what the CLI stores. The Statement
122
+ shows one calendar month's four claims side by side and exports them as CSV
123
+ without a total. The CLI remains the reference surface: the parity map in
124
+ Settings is derived from the registry, and a row's `full` or `partial`
125
+ coverage is checked against app source by
126
+ `test/dashboard-coverage-value.test.ts` rather than asserted.
113
127
 
114
128
  ## Intended direction
115
129
 
@@ -136,9 +150,9 @@ local-first from being read as offline.
136
150
 
137
151
  | Path | Operator control | Recipient | Data category | Non-claim |
138
152
  | --- | --- | --- | --- | --- |
139
- | Normal proxy route | Exact `provider_inference` controlled-cloud rule, then tool base URL and configured upstream | Configured AI provider | Provider request, which can contain prompts, source snippets, tool payloads, and provider credential | Segreant does not make provider retention/privacy promises. |
153
+ | Normal proxy route | Tool base URL pointed at Segreant. The official OpenAI and Anthropic APIs are built in (`segreant-builtin-provider-*`, either mode); any other configured upstream needs one exact `provider_inference` rule | Configured AI provider | Provider request, which can contain prompts, source snippets, tool payloads, and provider credential | Segreant does not make provider retention/privacy promises. |
140
154
  | OpenAI Costs pull | Explicit applied command, declared scope, environment-only key, and exact `provider_cost_observation` rule | Fixed OpenAI Costs endpoint | Narrow read-only provider cost request; normalized observations retained locally | Not a provider-account verification or a request-level reconciliation. |
141
- | Pricing/baseline refresh | Explicit command or configured refresh plus an exact rule | Operator-selected HTTPS manifest | Public manifest request; accepted normalized result/provenance stored locally | Not usage telemetry or provider invoice evidence. |
155
+ | Pricing/baseline refresh | The built-in public price list: `segreant pricing --refresh`, the configured refresh, or the first-sight lookup (on by default; `segreant pricing --auto off`), no rule needed. Any other manifest: explicit command plus an exact rule | The public price list, or an operator-selected HTTPS manifest | Public manifest request; accepted normalized result/provenance stored locally | Not usage telemetry or provider invoice evidence. |
142
156
  | Alert webhook | Explicit webhook configuration plus an exact rule | Operator-selected webhook | Configured alert summary | Not prompt, source, or credential transfer. |
143
157
  | Hosted judge | Explicit judge choice plus an exact rule | Configured judge provider | Bounded session excerpt for the selected tier | Not local-only evaluation. |
144
158
  | Team rollup | Explicit team push plus an exact rule | Operator-run team endpoint | Signed numeric aggregate | Not default telemetry or approved internet deployment. |
@@ -149,9 +163,16 @@ the provider or optional egress paths above.
149
163
  ### High-assurance egress modes
150
164
 
151
165
  - **Local locked** is the default and is enforceable for Segreant's own HTTP(S)
152
- transport: no non-loopback target is resolved or dialled. It permits a local
153
- inference service at a literal loopback address such as `127.0.0.1` or
154
- `localhost`.
166
+ transport: no non-loopback target is resolved or dialled except two built-in
167
+ routes, which hold in every mode. One is the user's own proxied requests to
168
+ the official provider APIs (`https://api.anthropic.com`,
169
+ `https://api.openai.com`; GET or POST under `/v1/`, purpose
170
+ `provider_inference`). The other is the public price list (one exact HTTPS
171
+ URL, GET only, sending nothing about the user; `segreant pricing --auto off`
172
+ stops Segreant requesting it by itself). It permits a local inference service
173
+ at a literal loopback address such as `127.0.0.1` or `localhost`. A malformed
174
+ persisted egress section loads as `invalid` and refuses every non-loopback
175
+ target, the built-in routes included, until it is repaired.
155
176
  - **Controlled cloud** is opt-in and rule-scoped. A rule does not authorize a
156
177
  hostname pattern, arbitrary query/redirect target, plaintext remote HTTP, or
157
178
  another purpose/data class. The process receipt records a redacted target
@@ -176,7 +197,8 @@ the provider or optional egress paths above.
176
197
  - Say no Segreant-hosted telemetry by default; do not generalize that default into
177
198
  an egress guarantee or claim that proxy traffic remains on the device.
178
199
  - Say `local_locked Segreant-process transport refused non-loopback HTTP(S)
179
- egress` only when that mode is active and receipts verify; say
200
+ egress other than its built-in routes` only when that mode is active and
201
+ receipts verify; say
180
202
  `controlled_cloud rule and receipt` for a permitted cloud request. Do not
181
203
  generalize either to the operating system, other applications, direct
182
204
  clients, or provider retention.
@@ -0,0 +1,38 @@
1
+ # CLI JSON contract
2
+
3
+ Use `--json` on a command that advertises machine output. Each completed read
4
+ emits one JSON document on stdout, including on a structured refusal. A command
5
+ that cannot produce a document exits non-zero with a concise diagnostic on
6
+ stderr and empty stdout. Human progress messages and stack traces never belong
7
+ in the JSON stream. Commands wrapping another process, persistent servers and
8
+ the status-line stdin protocol have their own output rules.
9
+
10
+ Every CLI JSON read response has the top-level integer `schemaVersion: 1`. Object
11
+ responses keep their existing fields beside that version. Responses that were
12
+ arrays, including request exports and audit rows, now use
13
+ `{ "schemaVersion": 1, "data": [...] }`. JSON request exports written with
14
+ `--out` use the same envelope as stdout. CSV output keeps its existing format.
15
+
16
+ Within a version, existing field meanings and types remain stable. New optional
17
+ fields may be added; readers should ignore fields they do not recognize. A
18
+ required field removal, a type change, a meaning change, or a different envelope
19
+ requires a new schema version and a documented migration. This promise begins
20
+ with the versioned 0.2.0 output; pre-versioned array consumers must read `data`.
21
+
22
+ A response that is itself a versioned document, such as a period-close record,
23
+ already carries `schemaVersion` with that document's meaning, and the CLI leaves
24
+ it unchanged rather than overwriting it.
25
+
26
+ The response version is separate from a ledger, billing evidence document,
27
+ signed receipt or pack schema. Backup/refusal output exposes the database
28
+ version as `ledgerSchemaVersion`; nested artifact versions and signed bodies
29
+ keep their own meanings. JSON formatting does not change those signed bodies.
30
+
31
+ Money still carries its original basis: metered usage, provider-billed cost,
32
+ allocated cost and realized value are distinct. Unknown stays null or the
33
+ documented sentinel; versioning never supplies missing evidence.
34
+
35
+ `test/cli-json-contracts.test.ts` derives command groups and aliases from the
36
+ actual dispatcher. Its fixture modes cover missing, empty, corrupt and large
37
+ synthetic ledgers, plus folders without Git. Adding a dispatch group requires
38
+ classifying it for read coverage or stating why it has another output protocol.
@@ -52,9 +52,27 @@ figure, and each stays on the machine under the Segreant home:
52
52
  - `scan_snapshots.repos_json` — repository locations discovered by a local
53
53
  scan, so the same disclosure applies as for `requests.cwd`.
54
54
 
55
+ Outside the ledger, `<home>/survival/` keeps git's answers to survival
56
+ measurement between runs: for each measured repository, commit hashes, the
57
+ repository-relative paths of files those commits touched, and per-file line
58
+ counts by commit. It holds no file contents, and the repository's own location
59
+ appears only as a hash in the file name. It is a cache, never evidence:
60
+ deleting the directory costs the next value run its time, not any figure, and
61
+ only the CLI and the dashboard it starts write it.
62
+
55
63
  Everything above is local. Only the declared egress paths below leave the
56
64
  Segreant process, and none of them carries these columns.
57
65
 
66
+ The 0.2.0 readers add local reads only; none of them opens an outbound connection. `import` and `scan` read
67
+ the session logs that Claude Code, Codex, opencode and Antigravity write on this
68
+ machine. They keep token counts, model names, working directories (stored as
69
+ `requests.cwd`) and the vendors' own rate-limit readings (`quota_events`; the
70
+ `detail` column holds at most 120 characters of the vendor's limit message). `plan`
71
+ reads only the `oauthAccount` plan fields of `~/.claude.json` and the `plan_type` of
72
+ the newest Codex session log. It never opens Claude Code's credentials file. A plan
73
+ price exists only when the operator sets it. `segreant-statusline` reads the JSON
74
+ that Claude Code passes on standard input and makes no network request.
75
+
58
76
  When an operator explicitly runs `segreant billing import --file ... --apply`,
59
77
  Segreant also stores an immutable, provider-declared billing-evidence ledger. V1
60
78
  accepts only a strict local OpenAI evidence JSON contract. It retains the file
@@ -75,6 +93,22 @@ provider session, or API key. The status is always
75
93
  `operator_declared_unverified`; it is not provider-account verification,
76
94
  reconciliation, or an instruction to change routing.
77
95
 
96
+ The dashboard can do the same local writes: declare a scope, import and adopt a
97
+ cost export, record a reconciliation, and set up cost centres, rules and
98
+ allocation runs. It does them through `POST /api/billing/write` and
99
+ `POST /api/allocation/write`. Neither route is one of the declared egress paths
100
+ below, and neither opens an outbound connection. They store exactly
101
+ what the matching CLI commands store, under the same rules. A billing import
102
+ from the browser keeps the same basename, digest and allowlisted fields as
103
+ `segreant billing import`, and not the raw file. Both routes answer only
104
+ requests that carry the `x-segreant-local: 1` header. A page on another origin
105
+ cannot send that header to the loopback dashboard without the browser's
106
+ pre-flight, and the dashboard answers no `OPTIONS`. They read a bounded body,
107
+ accept only allow-listed fields, and never quote a refused request or export
108
+ back in an error. In demo mode they refuse every write, while previews still
109
+ answer. The Statement's CSV download is a read of the same local ledger and
110
+ leaves the machine only if you send the file on.
111
+
78
112
  When an operator runs `segreant billing openai-costs pull ... --apply`, Segreant
79
113
  may make exactly one additional outbound type: a read-only `GET` to the fixed
80
114
  OpenAI Organization Costs endpoint at `https://api.openai.com/v1/organization/costs`.
@@ -91,8 +125,25 @@ recommendations. Failed/partial pulls retain failure metadata with no usable
91
125
  provider observations.
92
126
 
93
127
  All Segreant-process HTTP(S) transport is now governed by the egress boundary.
94
- The default `egress.mode: "local_locked"` permits literal loopback targets only
95
- and refuses non-loopback targets before DNS. A cloud operation needs
128
+ The default `egress.mode: "local_locked"` permits literal loopback targets, plus
129
+ two built-in routes, and refuses every other non-loopback target before DNS.
130
+
131
+ The first is your own traffic to your provider. A request your tool sends to
132
+ `https://api.anthropic.com` or `https://api.openai.com` (GET or POST under
133
+ `/v1/`, purpose `provider_inference`) is forwarded with no setup, receipted under
134
+ a `segreant-builtin-provider-*` rule id. It was going to that provider before
135
+ Segreant existed; Segreant only meters it on the way. Any other upstream (a
136
+ gateway, OpenRouter, a hosted open model) needs one exact rule, and a refused
137
+ request prints the command.
138
+
139
+ The second is Segreant's own price list: a GET of exactly
140
+ `https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json`
141
+ for purpose `pricing_refresh` and data class `pricing_manifest`, with no query or
142
+ fragment. It carries nothing about the user, its DNS answer must be public, and
143
+ it is receipted under rule id `segreant-builtin-price-list` like any cloud route.
144
+ Without it the rate card could never update and every new model would be priced
145
+ by a guess. Both routes hold in `controlled_cloud` mode too, so adding a rule for a webhook
146
+ never cuts off your provider or your price updates. Any other cloud operation needs
96
147
  `controlled_cloud` mode plus one enabled exact rule for its purpose, data class,
97
148
  method, HTTPS origin, and leading path. Before an allowed request is dialled,
98
149
  Segreant persists redacted local receipts for policy preflight and dial start; it
@@ -145,7 +196,7 @@ added without appearing on this page.
145
196
  | Purpose | Data class | What may cross | Reached by |
146
197
  | --- | --- | --- | --- |
147
198
  | `provider_inference` | `provider_request` | prompts, source snippets, tool payloads, and the caller's provider credential, exactly as the provider API requires | any tool pointed at the Segreant proxy |
148
- | `pricing_refresh` | `pricing_manifest` | nothing about you — a plain GET for a public pricing manifest | `segreant pricing --refresh`, or `pricing.autoRefresh` |
199
+ | `pricing_refresh` | `pricing_manifest` | nothing about you — a plain GET for a public pricing manifest | `segreant pricing --refresh`, `pricing.autoRefresh`, or a running Segreant's first-sight lookup (`pricing.lookupUnknownModels`, on by default) |
149
200
  | `market_refresh` | `market_manifest` | nothing about you — plain GETs for the public leaderboard and price files listed in `docs/MARKET-SOURCES.md` | `segreant market --refresh <source|all>` |
150
201
  | `baseline_refresh` | `baseline_manifest` | nothing about you — a plain GET for the manifest at an operator-supplied URL | `segreant baseline --refresh --url ...` |
151
202
  | `alert_delivery` | `alert_metadata` | configured alert summaries; never prompts, source, or credentials | `segreant alerts --set-webhook ...` |
@@ -187,14 +238,23 @@ this data to request in the first place.
187
238
 
188
239
  ## Optional outbound paths
189
240
 
241
+ One path is on by default:
242
+
243
+ - the first-sight price lookup. When a running Segreant prices a request by a
244
+ guess (the model is not on its rate card), it downloads the built-in public
245
+ price list once, at most once an hour, outside the request's path. Recorded
246
+ amounts are not rewritten; `segreant reprice` previews the correction and
247
+ `--apply` commits it. `segreant pricing --auto off` sets
248
+ `pricing.lookupUnknownModels` (and `pricing.autoRefresh`) to false.
249
+
190
250
  These paths are off unless an operator deliberately invokes or configures them:
191
251
 
192
252
  - `segreant pricing --refresh`, or `pricing.autoRefresh` with a configured manifest,
193
253
  downloads a public pricing manifest from the selected HTTPS URL. The request is
194
254
  a plain GET with no usage, prompt, or customer data; the accepted normalized
195
- card and redacted source provenance remain local under the Segreant home. It
196
- additionally needs an exact `pricing_refresh` egress rule in controlled-cloud
197
- mode.
255
+ card and redacted source provenance remain local under the Segreant home. The
256
+ built-in public price list needs no rule in either mode; any other manifest
257
+ URL needs an exact `pricing_refresh` egress rule in controlled-cloud mode.
198
258
  - `segreant baseline --refresh --url ...` downloads a baseline manifest from the
199
259
  URL supplied by the operator and needs an exact `baseline_refresh` rule.
200
260
  - `segreant alerts --set-webhook ...` sends configured alert summaries to the
package/docs/FAQ.md CHANGED
@@ -13,8 +13,15 @@ team rollup. [DATA-BOUNDARIES.md](DATA-BOUNDARIES.md) is the complete,
13
13
  current outbound and retention contract.
14
14
 
15
15
  **Can I make Segreant itself refuse all cloud traffic?**
16
- Yes. New configuration begins in `local_locked` mode, where Segreant refuses
17
- non-loopback HTTP(S) targets before DNS. A local model at `localhost` or
16
+ Yes, for everything Segreant would send on its own. New configuration begins in
17
+ `local_locked` mode, where Segreant refuses non-loopback HTTP(S) targets before
18
+ DNS, with two built-in routes: your own requests to the official OpenAI and
19
+ Anthropic APIs (they were going there anyway; Segreant meters them on the way),
20
+ and its download of the public price list, which sends nothing about you.
21
+ `segreant pricing --auto off` stops Segreant making that download by itself.
22
+ Your own provider requests are not something egress settings switch off: they go
23
+ out whenever a tool sends them through the proxy, so to stop them, stop the
24
+ proxy or point the tool back at the provider. A local model at `localhost` or
18
25
  `127.0.0.1` remains available. To permit a cloud route, use `segreant egress
19
26
  plan` to inspect one exact rule and `segreant egress apply --apply` to persist it;
20
27
  `segreant egress verify` validates the redacted local receipt chain. This is a
@@ -210,12 +217,19 @@ Usually the `/v1` double-version gotcha: if your client already appends
210
217
  `/chat/completions`, point it at `http://localhost:8090` **without** `/v1`. See
211
218
  [INTEGRATIONS.md](INTEGRATIONS.md).
212
219
 
220
+ **`egress` refuses `--path-prefix /v1/` in Git Bash on Windows.**
221
+ Git Bash rewrites any argument that starts with `/` into a Windows path, so
222
+ Segreant receives `C:/Program Files/Git/v1/` and refuses it (the refusal names
223
+ the value it received). Put `MSYS_NO_PATHCONV=1` in front of the command, or run
224
+ it from PowerShell or cmd, where `/v1/` arrives unchanged.
225
+
213
226
  **`doctor` says the rate card is stale.**
214
227
  `segreant pricing --refresh` pulls current rates from the community price feed
215
228
  (LiteLLM's model-price file — machine-readable, updated by hundreds of
216
229
  contributors within days of every model release; the GET sends nothing about
217
- you). It needs a reviewed `pricing_refresh` egress rule in controlled-cloud
218
- mode. For self-maintenance, `segreant pricing --auto` refreshes on start
230
+ you). The public price list is a built-in route in either egress mode, so it
231
+ needs no rule; a custom `pricing.manifestUrl` needs an exact `pricing_refresh`
232
+ rule in controlled-cloud mode. For self-maintenance, `segreant pricing --auto` refreshes on start
219
233
  whenever the table goes stale. A malformed or shrunken feed is refused and the
220
234
  current table kept — a bad refresh can never corrupt your pricing.
221
235
 
@@ -229,11 +243,31 @@ Every Segreant rate remains a local list-price estimate, not a provider invoice,
229
243
  contractual discount, credit, tax, or reconciliation result.
230
244
 
231
245
  **How does pricing stay correct as new models launch?**
232
- Three layers, in order: the refreshed community feed above (170+ models across
233
- Anthropic, OpenAI, Google); substring family-matching when an exact name is
234
- missing (a new `-preview` variant prices as its family); and a conservative
235
- flat fallback that marks every such request `~est` — surfaced in `doctor` as
236
- "% of spend on estimated rates", so pricing drift is measured, never silent.
246
+ Each request is priced by the first of these that knows its model:
247
+
248
+ 1. **A price you set.** `segreant pricing set <model>` with `--input` and
249
+ `--output` (USD per million tokens), `--like <model>` to price it as a model
250
+ on the card, or `--free` for a local model. Shown as "your price", never as
251
+ list price.
252
+ 2. **The rate card**, by exact model name. The bundled card is refreshed from
253
+ the public price list before each release.
254
+ 3. **The public price list, looked up on first sight.** When a running Segreant
255
+ meets a model the card does not know, it downloads the public price list
256
+ (at most once an hour, outside the request's path, sending nothing about
257
+ you). New requests then get the list price. Requests already recorded keep
258
+ their estimate until `segreant reprice` (a preview) and
259
+ `segreant reprice --apply`.
260
+ 4. **The nearest model on the card** (a new `-preview` variant prices as its
261
+ family), marked as such.
262
+ 5. **A generic rate** ($3 in, $15 out per million tokens), marked `~est`.
263
+
264
+ The generic rate is a guess in both directions: claude-haiku-5-5 costs $0.10 /
265
+ $0.50, so it read 30 times too high, and about a third of the models on the
266
+ card cost more than $3 / $15, so a premium model reads too low, including
267
+ against a budget cap. That is why the lookup comes before it.
268
+ `segreant pricing unknown` lists every model still priced by a guess, with its
269
+ requests and recorded cost, and `segreant pricing --auto off` turns the lookup
270
+ off.
237
271
 
238
272
  **Nothing shows under value / RoI.**
239
273
  Attach a git repo (`--repo .`) and let the maturity window elapse, or report outcomes
@@ -14,6 +14,16 @@ choice.
14
14
  > installing, prefix a command with `npx`, for example
15
15
  > `npx segreant demo --serve`. From a clone of the repository, run
16
16
  > `npm install`, `npm run build` and `npm link` once instead.
17
+ >
18
+ > **Windows, in a folder whose path contains `&`** (for example
19
+ > `Projects & Learning`): npm's `.cmd` launcher, and `npx` or `npm exec`, which
20
+ > use it, break at the ampersand in Command Prompt before Segreant starts. A
21
+ > global install lives under your user folder, so it is affected only if that
22
+ > path contains `&`. For a local install in such a folder, use
23
+ > PowerShell, where `segreant` runs npm's PowerShell launcher, or call Node
24
+ > directly: `node node_modules/segreant/bin/segreant.mjs demo --serve`. CI
25
+ > installs into a path with a space and an ampersand on Windows, macOS and
26
+ > Linux and runs these routes.
17
27
 
18
28
  ---
19
29
 
@@ -116,23 +126,20 @@ $env:ANTHROPIC_BASE_URL="http://localhost:8090"
116
126
  $env:OPENAI_BASE_URL="http://localhost:8090/v1"
117
127
  ```
118
128
 
119
- **Grant the provider route.** Segreant starts in **local-locked** mode and forwards
120
- nothing to a cloud provider until you allow that exact route. For OpenAI:
129
+ **No provider setup for OpenAI or Anthropic.** Your requests to their official
130
+ APIs go through as soon as Segreant starts: that traffic was already going to your
131
+ provider, and Segreant meters it on the way. Segreant still starts in
132
+ **local-locked** mode for everything it would send on its own (webhooks, team
133
+ rollups, hosted judging), which stays off until you allow it.
121
134
 
122
- ```bash
123
- segreant egress apply --apply --mode controlled_cloud \
124
- --id openai-inference --purpose provider_inference \
125
- --data-class provider_request --method POST \
126
- --origin https://api.openai.com --path-prefix /v1/
127
- ```
128
-
129
- For Anthropic, add a second rule (the OpenAI rule is kept):
135
+ Another provider (OpenRouter, a gateway, a hosted open model) needs one rule for
136
+ its address. A refused request prints the exact command, for example:
130
137
 
131
138
  ```bash
132
139
  segreant egress apply --apply --mode controlled_cloud \
133
- --id anthropic-inference --purpose provider_inference \
140
+ --id provider-openrouter-ai-8b97b9a4-post --purpose provider_inference \
134
141
  --data-class provider_request --method POST \
135
- --origin https://api.anthropic.com --path-prefix /v1/
142
+ --origin https://openrouter.ai --path-prefix /
136
143
  ```
137
144
 
138
145
  `segreant egress status` shows the active mode and rules. The full behaviour,
package/docs/GUIDE.md CHANGED
@@ -24,26 +24,25 @@ linked onto your `PATH`, run the same thing as `npm run segreant -- <verb>`.
24
24
 
25
25
  ## Egress control
26
26
 
27
- Segreant starts in **local-locked** mode. Before a cloud provider can receive
28
- routed traffic, grant only the exact route you intend to use. For the default
29
- OpenAI Responses/Chat API path:
27
+ Segreant starts in **local-locked** mode. Your requests to the official OpenAI
28
+ and Anthropic APIs go through with no setup: that traffic was already going to
29
+ your provider, and Segreant meters it on the way. The public price-list download
30
+ is built in the same way. Everything else Segreant could send on its own
31
+ (webhooks, team rollups, hosted judging) stays off until you add an exact rule.
30
32
 
31
- ```bash
32
- segreant egress apply --apply --mode controlled_cloud \
33
- --id openai-inference --purpose provider_inference \
34
- --data-class provider_request --method POST \
35
- --origin https://api.openai.com --path-prefix /v1/
36
- ```
37
-
38
- For Anthropic, add a second exact rule (this preserves the OpenAI rule):
33
+ Another provider (OpenRouter, a gateway, a hosted open model) needs one rule
34
+ for its address. A refused request prints the exact command, for example:
39
35
 
40
36
  ```bash
41
37
  segreant egress apply --apply --mode controlled_cloud \
42
- --id anthropic-inference --purpose provider_inference \
38
+ --id provider-openrouter-ai-8b97b9a4-post --purpose provider_inference \
43
39
  --data-class provider_request --method POST \
44
- --origin https://api.anthropic.com --path-prefix /v1/
40
+ --origin https://openrouter.ai --path-prefix /
45
41
  ```
46
42
 
43
+ The built-in routes hold in either mode, so adding a rule never cuts off your
44
+ provider or your price updates.
45
+
47
46
  Use `segreant egress status` to inspect the active mode/rules and
48
47
  `segreant egress verify` to verify the local receipt chain. Return to
49
48
  `local_locked` with `segreant egress apply --apply --mode local_locked`. These
@@ -65,8 +64,10 @@ tree from silently running older source.
65
64
  Onboarding — where you are, and how spend gets in with no wiring at all:
66
65
 
67
66
  ```
67
+ segreant Bare: this month, your plans, how much of the AI work
68
+ stayed in the code, and the next step
68
69
  segreant guide Where you are + the single next step, read from your
69
- real state — also what bare `segreant` shows (--json)
70
+ real state — the full checklist (--json)
70
71
  segreant scan [path] One-command setup: find the AI tools + git repos on
71
72
  this machine, preview a plan (read-only). --setup
72
73
  imports every detected tool and correlates every repo
@@ -75,7 +76,8 @@ segreant scan [path] One-command setup: find the AI tools + git repos
75
76
  the walk.
76
77
  segreant import <tool|all> NATIVE metering, no routing — reads the usage a tool
77
78
  already logs locally (works on subscriptions the proxy
78
- can never see). Tools: claude-code, opencode, codex.
79
+ can never see). Tools: claude-code, opencode, codex,
80
+ antigravity (or all).
79
81
  Idempotent; --watch keeps it live. (--days N, --json)
80
82
  segreant discover Correlate already-imported projects into per-project
81
83
  RoI without re-importing — `scan --setup`'s other half
@@ -83,6 +85,15 @@ segreant connect <tool> Wire a tool through the proxy as a connected sour
83
85
  (opencode, antigravity, or any OpenAI-compatible API)
84
86
  segreant sources Spend by connected source, at its honest depth
85
87
  (--all for all-time, --json)
88
+ segreant launch -- <command> Run one tool metered through the proxy while it runs;
89
+ with a cap set, a stopped proxy refuses unless
90
+ --allow-unmetered
91
+ segreant plan Your plans, what you pay, and the list-price work they
92
+ did (plan set <tool> <usd> records a price you pay)
93
+ segreant quota The vendors' own usage meters and the pace to their
94
+ reset, beside Segreant's count (--json)
95
+ segreant statusline --setup Prints the one line that makes Claude Code's status
96
+ line record its live usage meter
86
97
  ```
87
98
 
88
99
  Metering, governance, and value:
@@ -116,7 +127,8 @@ segreant team push --url <u> Cross-machine: sign + push this window's per-proj
116
127
  <name>, --json)
117
128
  segreant budget --recommend Evidence-limited cap recommendation from usage +
118
129
  realized value (applies a cap only; no routing or
119
- budget reallocation)
130
+ budget reallocation); --detail prints the full
131
+ decision record behind the verdict
120
132
  segreant alerts Governance alerts — spikes, throttling, runaway, value
121
133
  craters (--repo for value; --json; exits 1 if critical).
122
134
  Deliver to your webhook: --set-webhook <url>, then --notify
@@ -129,6 +141,18 @@ segreant report --kind K Wire an outcome gate: tested|merged|shipped|incid
129
141
  --commit <hash> [--verdict pass|fail] [--detail "…"]
130
142
  segreant exec -- <command> AMBIENT outcome capture — wrap a command once (e.g.
131
143
  `npm test`); every run reports its own exit code
144
+ segreant outcome record Preview a self-reported chat, image or other result;
145
+ --apply records it (--request ID, --session ID, or
146
+ --from/--to --tool to link it)
147
+ segreant outcome report Cost per accepted and used self-reported result, by
148
+ kind and model (--days N, --json)
149
+ segreant market Public quality per dollar by kind of work, from a
150
+ bundled dated snapshot — never mixed with your own
151
+ figures (--repo P shows yours beside it; --refresh
152
+ fetches through egress)
153
+ segreant evidence github Signed, offline CI evidence: `emit` runs in a
154
+ protected workflow, `import` verifies a pinned key and
155
+ the exact repository, branch, workflow and policy
132
156
  segreant receipt --repo <path> Emit signed value receipts (--pubkey to publish your
133
157
  identity; --verify <file> --key-id <id> to verify + pin)
134
158
  segreant yield --repo <path> Artifact persistence (legacy yield lens) — retained introduced lines per $
@@ -141,9 +165,28 @@ Operations:
141
165
  ```
142
166
  segreant init Write default config + print setup steps
143
167
  segreant doctor First-run health check — config, DB, proxy, caps, pricing
168
+ segreant help [all] The short list of commands; `help all` prints every
169
+ command and flag
170
+ segreant --version Print the installed version
144
171
  segreant config Show config and file paths (--json)
172
+ segreant features List optional subsystems and their switches;
173
+ features on|off <key> previews, --apply saves
174
+ segreant economic Exact economic events, roles, bases and legacy
175
+ coverage; period close/finalize/reopen controls
176
+ (--days N | --all, --as-of <ISO>, --json)
177
+ segreant alloc <action> Cost-centre allocation: centres, rules, and a
178
+ previewed split (--apply records it). See
179
+ "Cost-centre allocation" below
145
180
  segreant pricing --refresh Update the rate card from the community price feed
146
- (--auto opts into a refresh check on start when stale)
181
+ (--auto on|off: the start-time refresh when stale and
182
+ the first-sight lookup of an unknown model, together)
183
+ segreant pricing unknown Models still priced by a guess, with requests and
184
+ recorded cost (--json)
185
+ segreant pricing set <model> Give a model a price: --input <usd> --output <usd>
186
+ (per 1M tokens, optional --cache-read/--cache-write/--cache-write-1h),
187
+ --like <card-model>, or --free for a local model.
188
+ Shown as "your price", never as list price
189
+ segreant pricing unset <model> Remove a price you set
147
190
  segreant pricing --coverage Read-only per-model historical rate-card and match
148
191
  evidence (--days N or --all; --json for automation)
149
192
  segreant reprice Re-cost estimated rows against the current rate card
@@ -176,6 +219,12 @@ segreant plugin run --manifest <file> --request <file> --exec <path> --scope k=v
176
219
  segreant restore --from <file> --out <file>
177
220
  Preview a snapshot, or create a new verified
178
221
  database with --apply (never overwrites the active ledger)
222
+ segreant causal Retained randomized-study evidence: status, inspect,
223
+ replay verification and review-only estimates; never
224
+ changes routing (causal design|transport|family
225
+ --options <file> check study declarations)
226
+ segreant capital evaluate Review-only AI-capital decomposition from a bounded
227
+ JSON snapshot (--options <file>); no chargeback
179
228
  segreant demo Seed isolated, labeled synthetic data so every surface
180
229
  populates with no API key (--serve starts the dashboard
181
230
  on it; --clear removes it). Append --demo to today,
@@ -460,7 +509,21 @@ IDE / Agent → ANTHROPIC_BASE_URL/OPENAI_BASE_URL → Segreant proxy (:8090)
460
509
  versioned rate card, and logs it on-device. Prompt bodies are not stored by
461
510
  this metering path.
462
511
  3. **Runaway spend is capped** — soft warnings, hard caps, and a velocity guard
463
- can halt a looping agent before further proxy-routed provider usage.
512
+ can halt a looping agent before further proxy-routed provider usage. A cap
513
+ set with `segreant budget` takes effect on a running proxy without a
514
+ restart. The check happens before a request is sent, so requests already in
515
+ flight when the cap is crossed still finish: the overshoot is at most one
516
+ request per concurrent stream.
517
+
518
+ A request is priced by the first of these that knows its model: a price you
519
+ set (`segreant pricing set`), the rate card by exact name, the nearest model on
520
+ the card, then a generic $3 / $15 per million tokens. A running Segreant that
521
+ prices a request by either of the last two downloads the public price list once
522
+ (at most hourly, outside the request's path, sending nothing about you), so the
523
+ next request for that model gets its list price; an interactive
524
+ `scan --setup` does the same before it imports, then asks for a price for the
525
+ costliest models still guessed (Enter skips). Recorded rows keep their estimate
526
+ until `segreant reprice --apply`.
464
527
 
465
528
  The rate card is a local list-price estimate. Every newly calculated ledger row
466
529
  retains the exact rate-card SHA-256, source kind, and exact/family/fallback
@@ -27,20 +27,20 @@ upstream at the provider.** That's the whole integration.
27
27
  | `upstreams.openai` / `upstreams.anthropic` | `~/.segreant/config.json` | where Segreant forwards, after metering |
28
28
  | `egress` rule | `segreant egress apply --apply ...` | the exact cloud method/origin/path/data class Segreant may forward |
29
29
 
30
- For native OpenAI or Anthropic, the upstream defaults are correct, but a fresh
31
- Segreant install is `local_locked` and deliberately refuses cloud forwarding until
32
- you add an exact `provider_inference` egress rule. This is a second deliberate
33
- consent step: it records that a provider can receive the routed payload. You
34
- touch the upstream setting only to meter an OpenAI-*compatible* provider that
35
- isn't OpenAI (Gemini, OpenRouter, DeepSeek, Ollama, …).
30
+ For native OpenAI or Anthropic, the upstream defaults are correct and need no
31
+ other step: forwarding to their official APIs is built in, because that traffic
32
+ was already going there. You touch the upstream setting only to meter an
33
+ OpenAI-*compatible* provider that isn't OpenAI (Gemini, OpenRouter, DeepSeek,
34
+ Ollama, …). A remote one of those needs one exact `provider_inference` rule; a
35
+ refused request prints the command. A local server on `localhost` needs none.
36
36
 
37
- For example, before routing default OpenAI traffic:
37
+ For example, before routing traffic to a gateway:
38
38
 
39
39
  ```bash
40
40
  segreant egress apply --apply --mode controlled_cloud \
41
- --id openai-inference --purpose provider_inference \
41
+ --id provider-openrouter-ai-8b97b9a4-post --purpose provider_inference \
42
42
  --data-class provider_request --method POST \
43
- --origin https://api.openai.com --path-prefix /v1/
43
+ --origin https://openrouter.ai --path-prefix /
44
44
  ```
45
45
 
46
46
  The receipt chain is local and redacted: `segreant egress verify` checks its
@@ -158,8 +158,9 @@ alert webhooks, an explicitly selected hosted judge, a deliberate OpenAI Costs
158
158
  pull, and an opt-in numeric team rollup. The complete, current list and each
159
159
  retention control are in [DATA-BOUNDARIES.md](DATA-BOUNDARIES.md).
160
160
 
161
- New installations run Segreant-process HTTP(S) in `local_locked` mode. A
162
- controlled-cloud action needs an exact purpose/data/method/origin/path rule and
161
+ New installations run Segreant-process HTTP(S) in `local_locked` mode, with two
162
+ built-in routes: the user's own requests to the official provider APIs and the
163
+ public price-list download. Any other controlled-cloud action needs an exact purpose/data/method/origin/path rule and
163
164
  creates a redacted local receipt trail. This strengthens the Segreant boundary;
164
165
  it does not establish machine-wide egress control or a provider-side privacy
165
166
  guarantee.
@@ -47,7 +47,7 @@ collects nothing centrally.
47
47
  payment; offering it as a hosted service and selling Segreant itself are
48
48
  not allowed; each version becomes Apache 2.0 two years after publication
49
49
  (`LICENSING.md`). No function behaves differently for anyone: the license
50
- is a legal term, not a feature gate. Earlier commits carried MIT, copyright "Segreant contributors".
50
+ is a legal term, not a feature gate. Commits up to `28dc6dd` carried the MIT license under the project's earlier name, with the copyright line recorded in that commit's LICENSE.
51
51
  - `docs/RELEASE-GATE.md`'s "Product claims allowed at this stage" section
52
52
  fixes the precise language this project may use about itself and forbids
53
53
  overclaiming (not "AI financial advice," not "zero egress," not a verified