govyn 0.0.1 → 0.2.5

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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +263 -1
  3. package/configs/multi-provider.yaml +68 -0
  4. package/configs/openai-only.yaml +45 -0
  5. package/configs/team-setup.yaml +88 -0
  6. package/dist/action-logger.d.ts +128 -0
  7. package/dist/action-logger.js +356 -0
  8. package/dist/action-logger.js.map +1 -0
  9. package/dist/admin-cli.d.ts +2 -0
  10. package/dist/admin-cli.js +36 -0
  11. package/dist/admin-cli.js.map +1 -0
  12. package/dist/agents.d.ts +23 -0
  13. package/dist/agents.js +59 -0
  14. package/dist/agents.js.map +1 -0
  15. package/dist/alert-api.d.ts +14 -0
  16. package/dist/alert-api.js +355 -0
  17. package/dist/alert-api.js.map +1 -0
  18. package/dist/alert-manager.d.ts +77 -0
  19. package/dist/alert-manager.js +267 -0
  20. package/dist/alert-manager.js.map +1 -0
  21. package/dist/approval-api.d.ts +19 -0
  22. package/dist/approval-api.js +82 -0
  23. package/dist/approval-api.js.map +1 -0
  24. package/dist/approval-timeout.d.ts +29 -0
  25. package/dist/approval-timeout.js +45 -0
  26. package/dist/approval-timeout.js.map +1 -0
  27. package/dist/approval.d.ts +78 -0
  28. package/dist/approval.js +101 -0
  29. package/dist/approval.js.map +1 -0
  30. package/dist/auth.d.ts +47 -0
  31. package/dist/auth.js +335 -0
  32. package/dist/auth.js.map +1 -0
  33. package/dist/budget-api.d.ts +20 -0
  34. package/dist/budget-api.js +85 -0
  35. package/dist/budget-api.js.map +1 -0
  36. package/dist/budget-enforcer.d.ts +102 -0
  37. package/dist/budget-enforcer.js +294 -0
  38. package/dist/budget-enforcer.js.map +1 -0
  39. package/dist/cli.d.ts +15 -0
  40. package/dist/cli.js +200 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/config.d.ts +15 -0
  43. package/dist/config.js +267 -0
  44. package/dist/config.js.map +1 -0
  45. package/dist/cost-aggregator.d.ts +69 -0
  46. package/dist/cost-aggregator.js +305 -0
  47. package/dist/cost-aggregator.js.map +1 -0
  48. package/dist/cost-api.d.ts +29 -0
  49. package/dist/cost-api.js +128 -0
  50. package/dist/cost-api.js.map +1 -0
  51. package/dist/database-url.d.ts +6 -0
  52. package/dist/database-url.js +47 -0
  53. package/dist/database-url.js.map +1 -0
  54. package/dist/db-retention.d.ts +53 -0
  55. package/dist/db-retention.js +82 -0
  56. package/dist/db-retention.js.map +1 -0
  57. package/dist/db-schema.d.ts +17 -0
  58. package/dist/db-schema.js +167 -0
  59. package/dist/db-schema.js.map +1 -0
  60. package/dist/db-writer.d.ts +55 -0
  61. package/dist/db-writer.js +115 -0
  62. package/dist/db-writer.js.map +1 -0
  63. package/dist/db.d.ts +33 -0
  64. package/dist/db.js +78 -0
  65. package/dist/db.js.map +1 -0
  66. package/dist/events.d.ts +77 -0
  67. package/dist/events.js +12 -0
  68. package/dist/events.js.map +1 -0
  69. package/dist/health.d.ts +14 -0
  70. package/dist/health.js +49 -0
  71. package/dist/health.js.map +1 -0
  72. package/dist/index.d.ts +7 -0
  73. package/dist/index.js +14 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/init-wizard.d.ts +12 -0
  76. package/dist/init-wizard.js +206 -0
  77. package/dist/init-wizard.js.map +1 -0
  78. package/dist/log-api.d.ts +20 -0
  79. package/dist/log-api.js +371 -0
  80. package/dist/log-api.js.map +1 -0
  81. package/dist/log-rotator.d.ts +55 -0
  82. package/dist/log-rotator.js +157 -0
  83. package/dist/log-rotator.js.map +1 -0
  84. package/dist/loop-detector.d.ts +71 -0
  85. package/dist/loop-detector.js +122 -0
  86. package/dist/loop-detector.js.map +1 -0
  87. package/dist/persistence-types.d.ts +165 -0
  88. package/dist/persistence-types.js +2 -0
  89. package/dist/persistence-types.js.map +1 -0
  90. package/dist/persistence.d.ts +185 -0
  91. package/dist/persistence.js +785 -0
  92. package/dist/persistence.js.map +1 -0
  93. package/dist/policy-api.d.ts +25 -0
  94. package/dist/policy-api.js +347 -0
  95. package/dist/policy-api.js.map +1 -0
  96. package/dist/policy-engine.d.ts +76 -0
  97. package/dist/policy-engine.js +835 -0
  98. package/dist/policy-engine.js.map +1 -0
  99. package/dist/policy-file.d.ts +10 -0
  100. package/dist/policy-file.js +52 -0
  101. package/dist/policy-file.js.map +1 -0
  102. package/dist/policy-parser.d.ts +21 -0
  103. package/dist/policy-parser.js +560 -0
  104. package/dist/policy-parser.js.map +1 -0
  105. package/dist/policy-types.d.ts +216 -0
  106. package/dist/policy-types.js +8 -0
  107. package/dist/policy-types.js.map +1 -0
  108. package/dist/policy-watcher.d.ts +54 -0
  109. package/dist/policy-watcher.js +116 -0
  110. package/dist/policy-watcher.js.map +1 -0
  111. package/dist/pricing.d.ts +69 -0
  112. package/dist/pricing.js +93 -0
  113. package/dist/pricing.js.map +1 -0
  114. package/dist/prompt.d.ts +6 -0
  115. package/dist/prompt.js +47 -0
  116. package/dist/prompt.js.map +1 -0
  117. package/dist/providers/anthropic.d.ts +18 -0
  118. package/dist/providers/anthropic.js +61 -0
  119. package/dist/providers/anthropic.js.map +1 -0
  120. package/dist/providers/custom.d.ts +19 -0
  121. package/dist/providers/custom.js +54 -0
  122. package/dist/providers/custom.js.map +1 -0
  123. package/dist/providers/openai.d.ts +17 -0
  124. package/dist/providers/openai.js +48 -0
  125. package/dist/providers/openai.js.map +1 -0
  126. package/dist/proxy.d.ts +57 -0
  127. package/dist/proxy.js +477 -0
  128. package/dist/proxy.js.map +1 -0
  129. package/dist/router.d.ts +23 -0
  130. package/dist/router.js +89 -0
  131. package/dist/router.js.map +1 -0
  132. package/dist/runtime.d.ts +1 -0
  133. package/dist/runtime.js +139 -0
  134. package/dist/runtime.js.map +1 -0
  135. package/dist/security.d.ts +64 -0
  136. package/dist/security.js +422 -0
  137. package/dist/security.js.map +1 -0
  138. package/dist/server.d.ts +33 -0
  139. package/dist/server.js +1147 -0
  140. package/dist/server.js.map +1 -0
  141. package/dist/sqlite-schema.d.ts +6 -0
  142. package/dist/sqlite-schema.js +134 -0
  143. package/dist/sqlite-schema.js.map +1 -0
  144. package/dist/streaming.d.ts +24 -0
  145. package/dist/streaming.js +63 -0
  146. package/dist/streaming.js.map +1 -0
  147. package/dist/tokens.d.ts +45 -0
  148. package/dist/tokens.js +237 -0
  149. package/dist/tokens.js.map +1 -0
  150. package/dist/types.d.ts +344 -0
  151. package/dist/types.js +5 -0
  152. package/dist/types.js.map +1 -0
  153. package/package.json +66 -2
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GovynAI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,265 @@
1
1
  # Govyn
2
2
 
3
- Coming soon.
3
+ **The governance proxy for AI agents. Not an SDK. Not a wrapper. A wall.**
4
+
5
+ Every other agent governance tool is a library you import. If your agent — or any code it touches — makes a direct HTTP call, governance disappears. Govyn is different. It's an API proxy that holds your real API keys. Your agents only get a proxy URL. There is no alternative path to the real API. Governance is enforced by architecture, not by convention.
6
+
7
+ ```
8
+ SDK MODEL:
9
+ Agent [has real API key] → tries wrapper → OpenAI API
10
+ Agent [has real API key] → skips wrapper → OpenAI API ← governance bypassed
11
+
12
+ PROXY MODEL:
13
+ Agent [no real API key] → Govyn Proxy [has real key, enforces rules] → OpenAI API
14
+ Agent [no real API key] → OpenAI API directly → REJECTED (no key)
15
+ ```
16
+
17
+ SDK governance is a door lock — effective until someone finds another door.
18
+ Govyn is a wall. There are no other doors.
19
+
20
+ ---
21
+
22
+ ## Features
23
+
24
+ - **Per-agent budgets** — Set daily/monthly spend limits per agent with hard (block) or soft (warn) enforcement
25
+ - **Cost tracking** — Real-time cost aggregation across OpenAI, Anthropic, and compatible providers
26
+ - **Loop detection** — Automatically detect and block agents stuck in repetitive call patterns
27
+ - **Policy engine** — YAML-based rules: rate limits, model restrictions, require-approval gates, and custom policies
28
+ - **Action logging** — Every request logged with agent identity, cost, tokens, latency, and full context
29
+ - **Multi-provider** — Route OpenAI and Anthropic traffic through a single proxy with per-provider API keys
30
+ - **Locked-down management API** — Local-only by default, with optional admin API key and browser origin allowlist for remote dashboards
31
+ - **Zero agent changes** — Agents just point at a different base URL. No SDK imports, no code changes
32
+ - **Fail-open by default** — Proxy errors don't break your agents. Configurable to fail-closed for high-security deployments
33
+
34
+ ## Quickstart
35
+
36
+ Get from zero to a governed API call in under 5 minutes.
37
+
38
+ ### Prerequisites
39
+
40
+ - Node.js 20+
41
+ - An LLM API key (OpenAI or Anthropic)
42
+
43
+ ### Install and Configure
44
+
45
+ ```bash
46
+ npx govyn init
47
+ ```
48
+
49
+ The wizard walks you through provider selection, API key configuration, budget limits, agent naming, and persistence. It produces a local `govyn.config.yaml` in the current directory, defaults `database.url` to `sqlite:./govyn.db`, and can also point at PostgreSQL if you already run one.
50
+
51
+ ### Start the Proxy
52
+
53
+ ```bash
54
+ npx govyn
55
+ ```
56
+
57
+ The proxy starts on port 4000 by default.
58
+
59
+ ### Docker
60
+
61
+ ```bash
62
+ docker run -p 4000:4000 -e OPENAI_API_KEY=sk-... govyn
63
+ ```
64
+
65
+ Or with Docker Compose:
66
+
67
+ ```bash
68
+ docker-compose up
69
+ ```
70
+
71
+ For persistent self-hosting, mount a volume for your runtime files (`govyn.config.yaml`, `govyn.auth.json`, `govyn.db`, `policies.yaml`, and `logs/`) or point `database.url` at PostgreSQL instead of the default SQLite file.
72
+
73
+ ### Verify
74
+
75
+ ```bash
76
+ curl http://localhost:4000/health
77
+ # {"status":"ok"}
78
+ ```
79
+
80
+ ### Make Your First Governed Request
81
+
82
+ ```bash
83
+ curl http://localhost:4000/v1/openai/v1/chat/completions \
84
+ -H "Content-Type: application/json" \
85
+ -H "X-Govyn-Agent: my-first-agent" \
86
+ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}'
87
+ ```
88
+
89
+ The proxy forwards to OpenAI, tracks cost, enforces budget limits, and logs the action — all transparently.
90
+
91
+ ## Python SDK
92
+
93
+ For Python agents, use the `govynai` package for drop-in wrappers around the OpenAI and Anthropic SDKs:
94
+
95
+ ```bash
96
+ pip install govynai[all]
97
+ ```
98
+
99
+ ```python
100
+ from govynai import GovynOpenAI
101
+
102
+ client = GovynOpenAI(agent_id="my-agent")
103
+ response = client.chat.completions.create(
104
+ model="gpt-4o-mini",
105
+ messages=[{"role": "user", "content": "Hello"}]
106
+ )
107
+ ```
108
+
109
+ The wrapper automatically routes through your Govyn proxy, injects agent headers, and surfaces governance errors as typed exceptions. See [`python-sdk/`](./python-sdk/) for full documentation.
110
+
111
+ ## Configuration
112
+
113
+ Govyn uses a local `govyn.config.yaml` runtime file. Run `npx govyn init` to generate one interactively in your working directory, or create one manually. The repo ships example templates under [`configs/`](./configs/); it does not ship a ready-to-use operator config.
114
+
115
+ `govyn.config.yaml` is your deployment file. Keep it local to your environment and do not treat it as a shared repo sample.
116
+
117
+ The OSS dashboard also uses a local `govyn.auth.json` file for its single admin account. Create it during `npx govyn init` or later with `npx govyn admin setup`. Keep that file local and out of git too.
118
+
119
+ Govyn now uses SQLite by default for persistence. The default runtime database is `./govyn.db`, which powers approvals, alerts, cost history, and other durable operational data on a single host. Keep that file local and out of git too.
120
+
121
+ For the smallest local-only starting point, use [`configs/openai-only.yaml`](./configs/openai-only.yaml) or generate one with `npx govyn init`. A minimal manual config looks like this:
122
+
123
+ ```yaml
124
+ version: 1
125
+ proxy:
126
+ port: 4000
127
+ host: 127.0.0.1
128
+
129
+ providers:
130
+ openai:
131
+ base_url: https://api.openai.com
132
+ api_key_env: OPENAI_API_KEY
133
+ anthropic:
134
+ base_url: https://api.anthropic.com
135
+ api_key_env: ANTHROPIC_API_KEY
136
+
137
+ agents:
138
+ research-agent: {}
139
+
140
+ database:
141
+ url: sqlite:./govyn.db
142
+
143
+ budgets:
144
+ research-agent:
145
+ daily_limit: 10.00
146
+ monthly_limit: 100.00
147
+ limit_type: hard
148
+ ```
149
+
150
+ If you omit `database.url`, Govyn still defaults to `sqlite:./govyn.db` beside your config. Keeping it explicit in your local config makes the deployment shape clearer.
151
+
152
+ If you expose the proxy off-machine, add your own generated `agents.<name>.api_keys`. If you manage the proxy from a remote dashboard, create the local admin account on the host and add the dashboard origin under `security.trusted_origins`. Only set `security.admin_api_key_env` if you also want automation or break-glass API access.
153
+
154
+ ## Dashboard Auth
155
+
156
+ - The OSS dashboard uses one local admin username/password account.
157
+ - There is no Clerk, no email-based reset flow, no signup, and no OIDC/SAML in this repo.
158
+ - Create the admin account with `npx govyn admin setup`, or let `npx govyn init` create it during first-run setup.
159
+ - Reset the password locally with `npx govyn admin reset-password`.
160
+ - Browser logins use an `HttpOnly` session cookie. `GOVYN_ADMIN_API_KEY` remains available for automation and break-glass recovery, not normal dashboard sign-in.
161
+
162
+ ## Persistence
163
+
164
+ - Default OSS self-hosting: `database.url: sqlite:./govyn.db`
165
+ - SQLite is the recommended default for one host, one admin, and the normal self-hosted OSS setup.
166
+ - SQLite powers approvals, alerts, cost history, and other durable operational state without requiring a separate database service.
167
+ - Switch to PostgreSQL by setting `database.url: postgres://...` when you need a shared database, managed backups, or multiple Govyn instances against the same backend.
168
+ - The example configs under [`configs/`](./configs/) show the SQLite default and include commented PostgreSQL upgrade hints.
169
+
170
+ See [`configs/openai-only.yaml`](./configs/openai-only.yaml) for the canonical minimal example, or browse [`configs/`](./configs/) for more setups (single provider, multi-provider, teams).
171
+
172
+ ## Security Defaults
173
+
174
+ - Govyn does not ship any real agent keys, admin keys, or provider secrets. Every key shown in docs or UI is a placeholder or generated locally for the operator to adopt.
175
+ - The proxy binds to `127.0.0.1` by default so a fresh install is local-only.
176
+ - If you bind the proxy to a non-loopback host such as `0.0.0.0`, Govyn automatically requires `Authorization: Bearer <agent-api-key>` on proxied model requests. Configure those keys under `agents.<name>.api_keys`.
177
+ - You can explicitly set `security.require_agent_api_key: false`, but that creates an unauthenticated spend surface and is unsafe on shared or public networks.
178
+ - `/api/*` management endpoints are restricted to local requests by default.
179
+ - Once the local dashboard admin exists, browser management uses the dashboard session cookie instead of a pasted API key.
180
+ - To manage the proxy from another browser origin, add that origin under `security.trusted_origins` and sign in with the local admin username/password.
181
+ - `GOVYN_ADMIN_API_KEY` (or another env var via `security.admin_api_key_env`) is for automation, CLI tooling, and break-glass remote API access via `X-Govyn-Admin-Key`.
182
+ - Browser dashboards must be explicitly listed under `security.trusted_origins`. Localhost origins are allowed automatically for development.
183
+ - Browser-origin management requests from untrusted origins are rejected even on localhost, which blocks CSRF-style admin actions against a developer machine.
184
+ - `GET /api/approvals/:id` remains accessible without admin auth so the approval polling flow continues to work for agents.
185
+ - Approval tokens are single-use and bound to the original approved agent, target path, and request body.
186
+ - Alert webhooks reject loopback and private-network destinations, resolve DNS before connect, and block redirects to prevent SSRF against internal services.
187
+
188
+ ### Generating Agent Keys
189
+
190
+ - Generate your own long random value for every agent. Do not reuse provider API keys as agent API keys.
191
+ - The dashboard Settings page includes a browser-local generator and copy-ready YAML snippet. It helps you prepare local config only; it does not write proxy config, and the generated key is not sent to the proxy unless you manually add it to your config.
192
+ - If you prefer the terminal, `node -e "console.log('gvn_' + require('node:crypto').randomBytes(32).toString('hex'))"` prints a suitable key.
193
+
194
+ ## Policy Engine
195
+
196
+ Define governance rules in `policies.yaml`:
197
+
198
+ ```yaml
199
+ policies:
200
+ - name: require-approval-for-gpt4
201
+ match:
202
+ model: "gpt-4*"
203
+ action: require_approval
204
+ message: "GPT-4 usage requires human approval"
205
+
206
+ - name: block-production-models-at-night
207
+ match:
208
+ model: "gpt-4o"
209
+ schedule:
210
+ deny: "0 22 * * *-0 6 * * *"
211
+ action: block
212
+ ```
213
+
214
+ ## API Endpoints
215
+
216
+ | Endpoint | Description |
217
+ |----------|-------------|
218
+ | `GET /health` | Health check |
219
+ | `GET /api/costs` | Cost summaries per agent |
220
+ | `GET /api/budgets` | Budget status and remaining limits |
221
+ | `GET /api/logs` | Query action logs |
222
+ | `GET /api/policies` | List active policies |
223
+ | `POST /v1/openai/...` | Proxied OpenAI requests |
224
+ | `POST /v1/anthropic/...` | Proxied Anthropic requests |
225
+
226
+ ## Architecture
227
+
228
+ ```
229
+ ┌─────────────┐ ┌──────────────────────────────────┐ ┌─────────────┐
230
+ │ Agent A │────▶│ Govyn Proxy │────▶│ OpenAI │
231
+ │ (no key) │ │ │ │ API │
232
+ └─────────────┘ │ ┌──────────┐ ┌──────────────┐ │ └─────────────┘
233
+ │ │ Policy │ │ Budget │ │
234
+ ┌─────────────┐ │ │ Engine │ │ Enforcer │ │ ┌─────────────┐
235
+ │ Agent B │────▶│ └──────────┘ └──────────────┘ │────▶│ Anthropic │
236
+ │ (no key) │ │ ┌──────────┐ ┌──────────────┐ │ │ API │
237
+ └─────────────┘ │ │ Loop │ │ Action │ │ └─────────────┘
238
+ │ │ Detector │ │ Logger │ │
239
+ ┌─────────────┐ │ └──────────┘ └──────────────┘ │
240
+ │ Agent C │────▶│ │
241
+ │ (no key) │ │ Real API keys live here only │
242
+ └─────────────┘ └──────────────────────────────────┘
243
+ ```
244
+
245
+ Agents never hold real API keys. The proxy is the only path to the real APIs.
246
+
247
+ ## Project Structure
248
+
249
+ ```
250
+ govyn/
251
+ ├── src/ # Proxy server (TypeScript)
252
+ ├── python-sdk/ # Python SDK (govynai package)
253
+ ├── configs/ # Example configurations
254
+ ├── templates/ # Init wizard templates
255
+ ├── tests/ # Proxy test suite
256
+ └── docs/ # Documentation
257
+ ```
258
+
259
+ ## Contributing
260
+
261
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on submitting pull requests, reporting issues, and development setup.
262
+
263
+ ## License
264
+
265
+ [MIT](./LICENSE) — Copyright (c) 2026 GovynAI
@@ -0,0 +1,68 @@
1
+ # Govyn Config: Multi-Provider
2
+ # OpenAI + Anthropic + a custom local LLM (Ollama), two agents with different budgets.
3
+
4
+ version: 1
5
+
6
+ proxy:
7
+ port: 4000
8
+ host: 127.0.0.1 # Local-only default. For remote exposure, change this to 0.0.0.0 and add your own agent API keys.
9
+
10
+ providers:
11
+ openai:
12
+ base_url: https://api.openai.com
13
+ api_key_env: OPENAI_API_KEY
14
+
15
+ anthropic:
16
+ base_url: https://api.anthropic.com
17
+ api_key_env: ANTHROPIC_API_KEY
18
+
19
+ custom:
20
+ ollama:
21
+ base_url: http://localhost:11434 # Local Ollama instance
22
+ # No api_key_env needed for local Ollama
23
+
24
+ agents:
25
+ research-agent:
26
+ # Add your own generated api_keys only if you expose the proxy off-machine.
27
+ # api_keys:
28
+ # - gvn_generate_your_own_long_random_secret_here
29
+ coding-agent:
30
+ # api_keys:
31
+ # - gvn_generate_your_own_second_long_random_secret_here
32
+
33
+ database:
34
+ url: sqlite:./govyn.db # Default OSS persistence for approvals, alerts, and history.
35
+ # For a shared/team deployment later, switch to PostgreSQL:
36
+ # url: postgres://govyn:change-me@db.example.com:5432/govyn
37
+
38
+ # Custom pricing for models not in the built-in pricing table
39
+ pricing:
40
+ llama3:
41
+ input: 0.00 # Free for local models
42
+ output: 0.00
43
+
44
+ budgets:
45
+ research-agent:
46
+ daily_limit: 10.00
47
+ monthly_limit: 200.00
48
+ limit_type: hard
49
+ soft_warning_percent: 80
50
+
51
+ coding-agent:
52
+ daily_limit: 25.00
53
+ monthly_limit: 500.00
54
+ limit_type: soft # Soft limit: warn but don't block
55
+ soft_warning_percent: 70
56
+
57
+ security:
58
+ # Only needed for remote dashboard or admin API access.
59
+ # admin_api_key_env: GOVYN_ADMIN_API_KEY
60
+ # trusted_origins:
61
+ # - https://dashboard.example.com
62
+
63
+ logging:
64
+ enabled: true
65
+ directory: ./logs
66
+ default_mode: metadata
67
+ stdout: true
68
+ file: true
@@ -0,0 +1,45 @@
1
+ # Govyn Config: OpenAI-Only
2
+ # Minimal setup for proxying OpenAI requests with a single agent and daily budget.
3
+
4
+ version: 1
5
+
6
+ proxy:
7
+ port: 4000
8
+ host: 127.0.0.1 # Local-only default. For remote exposure, change this to 0.0.0.0 and add your own agent API key.
9
+
10
+ providers:
11
+ openai:
12
+ base_url: https://api.openai.com # Default OpenAI API endpoint
13
+ api_key_env: OPENAI_API_KEY # Reads from this environment variable
14
+
15
+ agents:
16
+ my-agent:
17
+ # Local-only example. If you expose the proxy on a non-loopback host,
18
+ # uncomment the lines below and generate your own long random secret.
19
+ # api_keys:
20
+ # - gvn_generate_your_own_long_random_secret_here
21
+
22
+ database:
23
+ url: sqlite:./govyn.db # Default OSS persistence. Govyn creates this local SQLite file automatically.
24
+ # For a shared or managed database later, switch to PostgreSQL:
25
+ # url: postgres://govyn:change-me@db.example.com:5432/govyn
26
+
27
+ budgets:
28
+ my-agent:
29
+ daily_limit: 5.00 # Hard stop at $5/day
30
+ monthly_limit: 100.00 # Hard stop at $100/month
31
+ limit_type: hard # hard = block requests, soft = warn only
32
+ soft_warning_percent: 80 # Emit warning header at 80% usage
33
+
34
+ security:
35
+ # Only needed for remote dashboard or admin API access.
36
+ # admin_api_key_env: GOVYN_ADMIN_API_KEY
37
+ # trusted_origins:
38
+ # - https://dashboard.example.com
39
+
40
+ logging:
41
+ enabled: true
42
+ directory: ./logs
43
+ default_mode: metadata # 'metadata' = summary only, 'full-payload' = include bodies
44
+ stdout: true # Print log lines to stdout (useful for Docker)
45
+ file: true # Write JSONL log files to disk
@@ -0,0 +1,88 @@
1
+ # Govyn Config: Team Setup
2
+ # Multi-agent team with soft/hard budgets and mixed logging modes.
3
+ # Full-payload logging for the debug agent, metadata-only for others.
4
+
5
+ version: 1
6
+
7
+ proxy:
8
+ port: 4000
9
+ host: 127.0.0.1 # Local-only default. For remote exposure, change this to 0.0.0.0 and add your own agent API keys.
10
+
11
+ providers:
12
+ openai:
13
+ base_url: https://api.openai.com
14
+ api_key_env: OPENAI_API_KEY
15
+
16
+ anthropic:
17
+ base_url: https://api.anthropic.com
18
+ api_key_env: ANTHROPIC_API_KEY
19
+
20
+ agents:
21
+ frontend-agent:
22
+ # Add your own generated api_keys only if you expose the proxy off-machine.
23
+ # api_keys:
24
+ # - gvn_generate_your_own_frontend_secret_here
25
+ loop_detection:
26
+ threshold: 5 # Stricter loop detection for UI agents
27
+ window_seconds: 30
28
+ cooldown_seconds: 120
29
+
30
+ backend-agent:
31
+ # api_keys:
32
+ # - gvn_generate_your_own_backend_secret_here
33
+ loop_detection:
34
+ threshold: 15 # More lenient for batch processing
35
+ window_seconds: 60
36
+ cooldown_seconds: 300
37
+
38
+ debug-agent:
39
+ # api_keys:
40
+ # - gvn_generate_your_own_debug_secret_here
41
+
42
+ database:
43
+ url: sqlite:./govyn.db # Default single-host persistence.
44
+ # For a shared team deployment or multiple Govyn instances, switch to PostgreSQL:
45
+ # url: postgres://govyn:change-me@db.example.com:5432/govyn
46
+
47
+ budgets:
48
+ frontend-agent:
49
+ daily_limit: 5.00
50
+ monthly_limit: 50.00
51
+ limit_type: hard # Hard limit: block at threshold
52
+ soft_warning_percent: 80
53
+
54
+ backend-agent:
55
+ daily_limit: 20.00
56
+ monthly_limit: 400.00
57
+ limit_type: soft # Soft limit: warn but allow
58
+ soft_warning_percent: 70
59
+
60
+ debug-agent:
61
+ daily_limit: 2.00
62
+ monthly_limit: 20.00
63
+ limit_type: hard
64
+ soft_warning_percent: 90
65
+
66
+ security:
67
+ # Only needed for remote dashboard or admin API access.
68
+ # admin_api_key_env: GOVYN_ADMIN_API_KEY
69
+ # trusted_origins:
70
+ # - https://dashboard.example.com
71
+
72
+ logging:
73
+ enabled: true
74
+ directory: ./logs
75
+ default_mode: metadata # Most agents get metadata-only logging
76
+ stdout: true
77
+ file: true
78
+ max_body_size: 524288 # 512KB max body capture
79
+ rotation_max_size_mb: 25 # Rotate at 25MB (smaller for teams)
80
+ rotation_interval_hours: 12 # Rotate every 12 hours
81
+ retention_days: 14 # Keep logs for 2 weeks
82
+ payload_retention_days: 3 # Keep payload files for 3 days
83
+
84
+ # Per-agent logging mode overrides
85
+ agent_modes:
86
+ debug-agent: full-payload # Full request/response bodies for debugging
87
+ frontend-agent: metadata # Summary only
88
+ backend-agent: metadata # Summary only
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Async action logger for the Govyn proxy server.
3
+ *
4
+ * Writes structured JSONL log entries for every proxied request.
5
+ * Supports two modes:
6
+ * - metadata: summary fields only (default)
7
+ * - full-payload: stores request/response bodies as separate JSON files
8
+ *
9
+ * Design:
10
+ * - log() is synchronous and non-blocking (zero added latency)
11
+ * - Entries are buffered in memory and flushed to disk on a 1-second interval
12
+ * - storePayload() is fire-and-forget async (errors logged to stderr)
13
+ * - Dual output: stdout AND/OR file, either disableable in config
14
+ */
15
+ import type { LogEntry, LoggingConfig, LoggingMode } from './types.js';
16
+ /**
17
+ * ActionLogger writes structured JSONL log entries for proxied requests.
18
+ *
19
+ * Non-blocking by design: log() pushes to an in-memory buffer that is
20
+ * flushed to disk on a 1-second unref'd interval. storePayload() writes
21
+ * payload files asynchronously without awaiting in the request path.
22
+ */
23
+ export declare class ActionLogger {
24
+ /** Exposed config for consumers that need to read settings (e.g., maxBodySize) */
25
+ readonly config: LoggingConfig;
26
+ /** Internal write buffer — entries waiting to be flushed to disk */
27
+ private buffer;
28
+ /** Path to the current active JSONL log file */
29
+ private currentFilePath;
30
+ /** Path to the payloads subdirectory */
31
+ private payloadsDir;
32
+ /** Periodic flush interval handle */
33
+ private flushInterval;
34
+ /** Log rotator for size/time-based rotation and retention cleanup */
35
+ private rotator;
36
+ constructor(config: LoggingConfig);
37
+ /**
38
+ * Read-only access to the log directory path.
39
+ * Used by the log query API to locate JSONL files.
40
+ */
41
+ get logDirectory(): string;
42
+ /**
43
+ * Get the full filesystem path to a payload file.
44
+ *
45
+ * @param payloadId - The payload ID (used as filename stem)
46
+ * @returns Full path to the payload JSON file
47
+ */
48
+ getPayloadPath(payloadId: string): string;
49
+ /**
50
+ * Log a structured entry. Non-blocking — adds to buffer and optionally writes to stdout.
51
+ * This is the zero-latency guarantee: no file I/O in the hot path.
52
+ * Automatically sets storage_region from config if not already set on the entry.
53
+ *
54
+ * @param entry - The structured log entry to record
55
+ */
56
+ log(entry: LogEntry): void;
57
+ /**
58
+ * Store a full payload (request + response bodies) as a separate JSON file.
59
+ * Fully async — fire and forget. Errors are logged to stderr but never thrown.
60
+ *
61
+ * @param payloadId - Unique ID for this payload (used as filename)
62
+ * @param requestBody - Raw request body buffer (or null)
63
+ * @param responseBody - Raw response body buffer (or null)
64
+ * @param truncated - Whether either body was truncated due to size limits
65
+ */
66
+ storePayload(payloadId: string, requestBody: Buffer | null, responseBody: Buffer | null, truncated: boolean): void;
67
+ /**
68
+ * Flush buffered entries to the current JSONL file.
69
+ * Uses synchronous append to ensure atomicity of the batch write.
70
+ */
71
+ flush(): void;
72
+ /**
73
+ * Get the logging mode for a specific agent.
74
+ * Returns the agent-specific override if set, otherwise the default mode.
75
+ *
76
+ * @param agentId - The agent to look up
77
+ * @returns The LoggingMode to use for this agent
78
+ */
79
+ getMode(agentId: string): LoggingMode;
80
+ /**
81
+ * Set the logging mode for a specific agent at runtime.
82
+ * Does NOT persist to YAML — runtime-only toggle.
83
+ *
84
+ * @param agentId - The agent to configure
85
+ * @param mode - The logging mode to set
86
+ */
87
+ setMode(agentId: string, mode: LoggingMode): void;
88
+ /**
89
+ * Get the path of the current active JSONL log file.
90
+ * Useful for rotation logic and diagnostics.
91
+ */
92
+ getCurrentFilePath(): string;
93
+ /**
94
+ * Purge all log entries and associated payload files older than the given date.
95
+ *
96
+ * - Reads all JSONL files (current + rotated) in the log directory
97
+ * - For each file: filters out entries with timestamps before the date
98
+ * - Deletes payload files for removed entries that have has_payload=true
99
+ * - Handles gzipped rotated files: decompress, filter, recompress or delete
100
+ * - Returns counts of deleted log entries and deleted payload files
101
+ *
102
+ * @param date - Purge entries with timestamps strictly before this date
103
+ * @returns Counts of deleted log entries and payload files
104
+ */
105
+ purgeBefore(date: Date): {
106
+ deletedLogs: number;
107
+ deletedPayloads: number;
108
+ };
109
+ /**
110
+ * Purge entries from a plain JSONL file.
111
+ * Rewrites the file with only entries newer than the cutoff date.
112
+ */
113
+ private purgeJsonlFile;
114
+ /**
115
+ * Purge entries from a gzipped rotated JSONL file.
116
+ * Decompresses, filters, and either recompresses or deletes if empty.
117
+ */
118
+ private purgeGzipFile;
119
+ /**
120
+ * Close the logger: flush remaining buffer and stop the flush interval.
121
+ */
122
+ close(): void;
123
+ /**
124
+ * Generate a unique ID for log entries and payload files.
125
+ * Uses crypto.randomUUID() for guaranteed uniqueness.
126
+ */
127
+ static generateId(): string;
128
+ }