Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
273 commits
Select commit Hold shift + click to select a range
d8e077b
Give a signed-in ChatGPT plan the Codex model, and the store rather t…
davidmckayv Sep 7, 2026
63eb698
Empty the plan token this app has stopped writing
davidmckayv Sep 7, 2026
4825ccb
End the install with a question the Bot has to answer
davidmckayv Sep 7, 2026
3079696
Keep credentials in the machine's own store, not in the .env
davidmckayv Sep 7, 2026
0ddba6f
Give the secondary buttons the class the stylesheet actually defines
davidmckayv Sep 7, 2026
af4ea71
Store a credential through the Keychain itself, not through the secur…
davidmckayv Sep 7, 2026
f04fbe2
Mint the generated secrets once per deployment, not once per start
davidmckayv Sep 7, 2026
b358264
Stop the Bot that was picked, and stop refusing to start because of it
davidmckayv Sep 7, 2026
f8776c1
Make the ChatGPT sign-in work, and say what went wrong when it does not
davidmckayv Sep 7, 2026
9d38e9a
Give the window an Edit menu, and let a plan pick the Bot that can sp…
davidmckayv Sep 8, 2026
4534215
Make the CopilotKit sign-in work, which took four shape mismatches to…
davidmckayv Sep 8, 2026
50b872c
Stop a model name outliving the answer that chose it
davidmckayv Sep 8, 2026
1a801c9
Say why a conversation has no messages, instead of showing a blank wi…
davidmckayv Sep 8, 2026
b0cf273
Install the container engine, instead of telling somebody to go and g…
davidmckayv Sep 8, 2026
9f087f2
Let an endpoint that needs no key be connected
davidmckayv Sep 8, 2026
927aba0
Let a Bot answer from an endpoint that needs no key
davidmckayv Sep 8, 2026
b280799
Send a placeholder key to an endpoint that reads no key
davidmckayv Sep 8, 2026
2008f67
Serve the installed app without a development server
davidmckayv Sep 8, 2026
bce6e5c
Show the CopilotKit sign-in address, the way the plan sign-ins do
davidmckayv Sep 8, 2026
9c631a4
Stop the host processes on Windows, where Stop was leaving them running
davidmckayv Sep 8, 2026
9d07744
Find the host processes by pid file, so the worker is stopped too
davidmckayv Sep 8, 2026
4cc5fc5
Ask the credential store once per run, not once per screen
davidmckayv Sep 8, 2026
fb52a1b
Merge main
davidmckayv Sep 9, 2026
5ea56ee
Scope the Keychain's service name to the Keychain
davidmckayv Sep 9, 2026
3948d33
Fix credential migration purge ordering
davidmckayv Sep 9, 2026
03258a9
Fix picked harness run routes
davidmckayv Sep 9, 2026
cdd72dc
Verify Windows host identity before cleanup
davidmckayv Sep 9, 2026
0b01261
fix: load auth headers for remote mastra agents
davidmckayv Sep 9, 2026
c013a7d
fix(desktop): fetch deployment before harness image resolution
davidmckayv Sep 9, 2026
a247f41
Fix CrewAI Bot role preservation
davidmckayv Sep 9, 2026
db21e62
fix server mastra middleware cloning
davidmckayv Sep 9, 2026
7f9ad26
fix app proxy websocket session headers
davidmckayv Sep 9, 2026
4b67736
Normalize blank OpenAI base URL in Python harness
davidmckayv Sep 9, 2026
bda60a1
fix: preserve openbot context for mastra runs
davidmckayv Sep 9, 2026
a762b15
fix: keep failed channel history reads neutral
davidmckayv Sep 9, 2026
d8e1b1b
fix anthropic picked harness provider config
davidmckayv Sep 9, 2026
3af64e1
fix: mount chatgpt token store directory
davidmckayv Sep 9, 2026
cfb75f9
Fix provider-scoped plan sign-ins
davidmckayv Sep 9, 2026
a99040c
Fix Ask model recovery state
davidmckayv Sep 9, 2026
68d349c
test: isolate plugin-store audit refusal row
davidmckayv Sep 9, 2026
ffabbfc
test: update remote agent wrapper assertions
davidmckayv Sep 9, 2026
b4908b5
fix: use native Mastra transport for desktop ask
davidmckayv Sep 9, 2026
fb57f00
test: isolate keychain regressions from real stores
davidmckayv Sep 9, 2026
68b96ab
fix desktop empty project retry
davidmckayv Sep 9, 2026
f03216b
fix: split passive and interactive vault reads
davidmckayv Sep 9, 2026
bec2c9f
Fix Mastra receiver OpenBot instructions
davidmckayv Sep 9, 2026
362dc8d
Add Python harness CI regressions
davidmckayv Sep 9, 2026
61962b9
test: cover saved plan restoration
davidmckayv Sep 9, 2026
ba6914e
fix(desktop): carry byo agent endpoint through setup
davidmckayv Sep 9, 2026
b14e6a8
style(desktop): format saved credential notice
davidmckayv Sep 9, 2026
999b8b9
test(desktop): isolate Rust temp roots
davidmckayv Sep 9, 2026
5ca2f6b
test(server): stub vertex provider in bun preload
davidmckayv Sep 9, 2026
8c4cb1b
test: satisfy vault cache clippy slice refs
davidmckayv Sep 9, 2026
9046314
fix desktop shutdown root retention
davidmckayv Sep 9, 2026
be60fea
fix: isolate compatible endpoint api keys
davidmckayv Sep 9, 2026
87b0566
Reject missing saved model API keys
davidmckayv Sep 9, 2026
06cc5e4
Add saved key startup boundary fixture
davidmckayv Sep 9, 2026
d1cd03e
fix(desktop): scope saved setup state to root edits
davidmckayv Sep 9, 2026
178368f
Fix compatible endpoint scheme validation
davidmckayv Sep 9, 2026
06eb6e2
Repair engine readiness compose install
davidmckayv Sep 9, 2026
a5a417d
fix: preserve ask body read errors
davidmckayv Sep 9, 2026
004f07a
fix(desktop): read managed bot logs for fallback ask failures
davidmckayv Sep 9, 2026
53e8071
fix(desktop): validate compatible endpoint credentials
davidmckayv Sep 9, 2026
eacdd13
fix(desktop): invalidate configured loads on root edits
davidmckayv Sep 9, 2026
ce1461a
fix(langgraph): preserve providers for colon-bearing model IDs
davidmckayv Sep 9, 2026
4f98e69
fix(desktop): omit API keys from plan choices
davidmckayv Sep 9, 2026
d47ed7d
fix(desktop): detect IPv6-only port conflicts
davidmckayv Sep 9, 2026
a5126b5
fix(desktop): reject invalid provider endpoint hosts
davidmckayv Sep 9, 2026
72ee1fc
fix(desktop): require a usable BYO agent URL host
davidmckayv Sep 9, 2026
e6fc796
fix(desktop): surface Windows setup detection failures
davidmckayv Sep 9, 2026
be4c781
fix(desktop): protect Linux vault files before writing secrets
davidmckayv Sep 9, 2026
82ea997
fix(app): contain static paths within the dist directory
davidmckayv Sep 9, 2026
85f33fb
fix(app): refuse malformed static URL encodings
davidmckayv Sep 9, 2026
1b7bbf9
fix(desktop): block disabled Virtual Machine Platform
davidmckayv Sep 9, 2026
b5e6383
fix(app): wait for upstream websocket handshake
davidmckayv Sep 9, 2026
e57a5df
fix(desktop): give administrators actionable WSL setup instructions
davidmckayv Sep 9, 2026
d8685b3
fix(desktop): recognize localized WSL kernel versions
davidmckayv Sep 9, 2026
fc36eeb
fix(app): refresh channel history notices after Bot activity
davidmckayv Sep 9, 2026
e71040b
fix(desktop): keep passive credential hydration out of protected storage
davidmckayv Sep 9, 2026
37fe316
fix(server): report unavailable connected-vendor guidance
davidmckayv Sep 9, 2026
1ef13d0
test(crewai): restore role test authentication token after teardown
davidmckayv Sep 9, 2026
8160810
fix(desktop): use the OpenBot orb for app and tray icons
davidmckayv Sep 9, 2026
176bc27
fix(desktop): reject incomplete DPAPI stdin writes
davidmckayv Sep 9, 2026
eee1860
fix(server): report standing instruction read failures
davidmckayv Sep 9, 2026
d7b965e
fix(desktop): restore hidden window on macOS reopen
davidmckayv Sep 9, 2026
3c6ca95
fix(desktop): preserve unreadable settings files
davidmckayv Sep 9, 2026
c66e4e1
fix(desktop): restore second instances outside the async listener
davidmckayv Sep 9, 2026
99bb943
fix(server): report skill selection read failures
davidmckayv Sep 9, 2026
d093f06
fix(mastra): default blank model identifiers
davidmckayv Sep 9, 2026
d6464ee
fix(desktop): report Linux credential read failures
davidmckayv Sep 9, 2026
ab1e239
fix(agent-mastra): validate mastra listen port
davidmckayv Sep 9, 2026
02ff9a4
fix(server): diagnose discovery audit write failures
davidmckayv Sep 9, 2026
e4e416d
fix: normalize crewai blank model config
davidmckayv Sep 9, 2026
b9669ad
fix(desktop): fail closed on compose service inspection errors
davidmckayv Sep 9, 2026
d369733
fix(desktop): harden compose service inspection proofs
davidmckayv Sep 9, 2026
1380d07
fix: validate configured ChatGPT auth file
davidmckayv Sep 9, 2026
1409407
test(server): restore tool selection model env
davidmckayv Sep 9, 2026
a189d25
test(server): prove tool selection env restoration
davidmckayv Sep 9, 2026
0fd77de
test(server): harden tool selection env proof
davidmckayv Sep 9, 2026
96bbaf9
fix(agent-crewai): project provider chat messages
davidmckayv Sep 9, 2026
6ea30d8
fix: route google provider through google genai
davidmckayv Sep 9, 2026
13e62bf
fix(server): reject spoofed mastra governance context
davidmckayv Sep 9, 2026
ec170c9
fix(agent-crewai): forward caller tools to litellm
davidmckayv Sep 9, 2026
0f145dc
fix: pass anthropic base url to picked harness
davidmckayv Sep 9, 2026
dd699c5
test(server): clean up custom server upsert credential
davidmckayv Sep 9, 2026
2cf94e3
fix(server): restrict tombstones to live channels
davidmckayv Sep 9, 2026
8953582
fix: surface process cleanup failures
davidmckayv Sep 9, 2026
9ca933b
fix: propagate cleanup command failures
davidmckayv Sep 9, 2026
c8012da
test: verify every secret-bearing compose port binding
davidmckayv Sep 9, 2026
2671ec6
test(server): prove the current tool refusal audit payload
davidmckayv Sep 9, 2026
ceeb34c
fix: reject unavailable Windows cleanup evidence
davidmckayv Sep 9, 2026
2a5bbd5
fix: retain Windows pidfile after incomplete cleanup
davidmckayv Sep 9, 2026
e4cc50c
fix: persist host pidfiles with strict atomic replacement
davidmckayv Sep 9, 2026
9de5989
test(server): restore borrowed Notion client credentials
davidmckayv Sep 9, 2026
b632108
fix(desktop): verify Unix process ownership before cleanup
davidmckayv Sep 9, 2026
5f14d29
fix(server): preserve deleted Bot refusal through runtime clones
davidmckayv Sep 9, 2026
d33de26
fix(app): validate built serving ports with shared contract
davidmckayv Sep 9, 2026
998c0bf
fix(app): retain failed mount history notice
davidmckayv Sep 9, 2026
18996f9
fix(app): restore durable history around shared message anchors
davidmckayv Sep 9, 2026
21348b0
fix(desktop): suppress credential authorization UI during normal actions
davidmckayv Sep 9, 2026
76ca4ee
fix(desktop): preserve existing installation encryption keys
davidmckayv Sep 9, 2026
6d11512
fix(langgraph): default blank providers before model routing
davidmckayv Sep 9, 2026
d7ffe55
fix(app): restore readable channel history on mount
davidmckayv Sep 9, 2026
7712289
test(server): bind plugin audit assertions to each invocation
davidmckayv Sep 9, 2026
54c51fa
fix(desktop): recover one refused Keychain operation
davidmckayv Sep 9, 2026
f851411
fix(desktop): restore noninteractive Windows vault invocation
davidmckayv Sep 9, 2026
ee1651e
fix(langgraph): select defaults for the configured provider
davidmckayv Sep 9, 2026
9cf899b
fix(desktop): retire failed starts before retry cleanup
davidmckayv Sep 10, 2026
c9994ac
Merge main while preserving desktop recovery and audit handling
davidmckayv Sep 10, 2026
6c42d0d
Use root-scoped file credential storage
davidmckayv Sep 10, 2026
9cd428e
Add credential root boundary proof tests
davidmckayv Sep 10, 2026
62a851c
test(server): prove fixture listener teardown
davidmckayv Sep 10, 2026
bd16f2d
fix(server): preserve handoff initiator through delivery
davidmckayv Sep 10, 2026
79a201a
test(server): bind handoff delivery signer proof
davidmckayv Sep 10, 2026
5e2750d
fix(desktop): retain selected root for menu stop
davidmckayv Sep 10, 2026
fefcf15
fix(langgraph): bind and execute forwarded tools
davidmckayv Sep 10, 2026
a77b902
fix app bot default to picked harness
davidmckayv Sep 10, 2026
db1b680
test: tighten bot default route fixture
davidmckayv Sep 10, 2026
3de6105
test: document bot route wiring cast
davidmckayv Sep 10, 2026
91a0e6f
fix(app): ignore self echoed channel activity
davidmckayv Sep 10, 2026
80e4c09
fix(app): treat malformed thread history as unavailable
davidmckayv Sep 10, 2026
100ab38
fix(server): filter reserved mastra context fields
davidmckayv Sep 10, 2026
a8e77d4
fix(app): reject decoded nul static paths
davidmckayv Sep 10, 2026
e325294
fix(server): preload EventSource for production loader
davidmckayv Sep 10, 2026
f6d8ad8
test(server): accept windows loader db boundary
davidmckayv Sep 10, 2026
ce81d08
fix(scripts): stop legacy server on restart
davidmckayv Sep 10, 2026
8d645f9
fix(langgraph): preserve parallel tool call stream lifecycles
davidmckayv Sep 10, 2026
583efc6
fix(app): bound stalled thread history reads
davidmckayv Sep 10, 2026
9efe9d0
style(server): wrap loader boundary assertion
davidmckayv Sep 10, 2026
a0ef1b6
fix landing default agent selection
davidmckayv Sep 10, 2026
cc148a4
fix(computer): skip unavailable optional SPIRE sockets
davidmckayv Sep 10, 2026
61bd557
fix(desktop): validate BYO harness URLs before persistence
davidmckayv Sep 10, 2026
623f0d7
fix desktop start on dead compose services
davidmckayv Sep 10, 2026
d0eab4f
fix(desktop): select bundled bot services by provider
davidmckayv Sep 10, 2026
9597a1a
fix(desktop): report unreadable DPAPI credential files
davidmckayv Sep 10, 2026
617d542
fix(desktop): distinguish DPAPI read diagnostics
davidmckayv Sep 10, 2026
722c649
fix(desktop): clear saved model intent for no model
davidmckayv Sep 10, 2026
4e5d0a4
fix(desktop): preserve private storage file boundaries
davidmckayv Sep 10, 2026
d62ec47
fix(desktop): detect localized WSL1 status
davidmckayv Sep 10, 2026
a84882b
fix(desktop): parse WSL default version label precisely
davidmckayv Sep 10, 2026
b694161
fix(desktop): read WSL default version from registry
davidmckayv Sep 10, 2026
ee7a73f
fix(desktop): fail loud on WSL registry read errors
davidmckayv Sep 10, 2026
20edb11
fix(desktop): keep WSL registry probe strict and readable
davidmckayv Sep 10, 2026
111e992
docs(desktop): clarify WSL registry version probe
davidmckayv Sep 10, 2026
863d1c2
fix(desktop): fail loud on Windows MSI cleanup errors
davidmckayv Sep 10, 2026
3fae77b
test(desktop): gate MSI process proof to Unix
davidmckayv Sep 10, 2026
7fb063a
fix(desktop): keep Podman command failure evidence
davidmckayv Sep 10, 2026
670e801
test(desktop): gate Podman process fixture import
davidmckayv Sep 10, 2026
bfaa26c
fix(desktop): reject line breaks in dotenv settings
davidmckayv Sep 10, 2026
ac99ffb
fix(compose): map selected harness callback host
davidmckayv Sep 10, 2026
4e82aa5
fix(desktop): fail closed on partial Windows host ownership
davidmckayv Sep 10, 2026
79a5a6d
fix(desktop): retire host children after ownership record failure
davidmckayv Sep 10, 2026
60da529
fix(desktop): retain host ownership when cleanup fails
davidmckayv Sep 10, 2026
fa5e2a4
fix(desktop): verify root ownership before adopting running stack
davidmckayv Sep 10, 2026
dfe5bac
fix(desktop): require Unix server port ownership before adoption
davidmckayv Sep 10, 2026
61094c5
fix(desktop): restore endpoint-scoped saved model credentials
davidmckayv Sep 10, 2026
025f12c
fix(app): report bot roster load failures
davidmckayv Sep 10, 2026
409d696
fix bot route hidden agent detail lookup
davidmckayv Sep 10, 2026
a38c3e1
fix bot route detail cache collision
davidmckayv Sep 10, 2026
69d94bd
fix channel new agent load errors
davidmckayv Sep 10, 2026
24652e3
fix channel new stale detail error state
davidmckayv Sep 10, 2026
504a764
fix(server): cancel pending agent builds on Stop
davidmckayv Sep 10, 2026
6c0d8b1
fix home fallback agent selection
davidmckayv Sep 10, 2026
0955c6b
fix same-timestamp activity refresh
davidmckayv Sep 10, 2026
8c475b2
fix LangGraph test imports from repository root
davidmckayv Sep 10, 2026
63666d8
fix empty history refresh retry
davidmckayv Sep 10, 2026
0c4b552
fix no-text run activity reporting
davidmckayv Sep 10, 2026
87c0302
fix cached channel activity restore
davidmckayv Sep 10, 2026
d7abeac
fix desktop Start for saved compatible endpoints
davidmckayv Sep 10, 2026
8c31494
fix empty bot agent query default
davidmckayv Sep 10, 2026
4a8dce3
fix BYO startup to skip the local harness service
davidmckayv Sep 10, 2026
b9b110f
fix bundled agent registry eligibility across provider changes
davidmckayv Sep 10, 2026
07ca566
Support container endpoint override for compatible models
davidmckayv Sep 10, 2026
cf6ed14
fix(app): encode agent IDs in API paths
davidmckayv Sep 10, 2026
05851c0
fix(server): authenticate picked harness without bundled bot
davidmckayv Sep 10, 2026
0f45454
fix(server): abort wrapped remote agent runs
davidmckayv Sep 10, 2026
03f36bb
fix(server): canonicalize managed endpoint identity
davidmckayv Sep 10, 2026
934d61c
test(compose): verify compatible endpoint resolution
davidmckayv Sep 10, 2026
c41342b
fix(desktop): retain ownership after partial host launch
davidmckayv Sep 10, 2026
c20838b
fix(server): scope tenant package grant cleanup
davidmckayv Sep 10, 2026
20b580c
fix(server): protect tenant package channel ownership
davidmckayv Sep 10, 2026
49327cd
fix(desktop): scope computer shutdown to deployment namespace
davidmckayv Sep 10, 2026
868ee21
fix(server): use selected compatible model for built-in agents
davidmckayv Sep 10, 2026
03ac0f5
test(supervisor): isolate health-capable Docker lifecycle fixtures
davidmckayv Sep 10, 2026
b84dc36
fix(server): honor explicit openai compatible model
davidmckayv Sep 10, 2026
577b463
fix(desktop): restore only the selected owned deployment
davidmckayv Sep 10, 2026
e10ec5f
fix(desktop): verify app listener ownership before adoption
davidmckayv Sep 10, 2026
3cd7f80
fix(desktop): keep Quit responsive during cleanup
davidmckayv Sep 10, 2026
7f9c8f3
fix(desktop): cancel initial startup when Stop retires its run
davidmckayv Sep 10, 2026
bc3925c
fix(desktop): verify Windows parent process creation order
davidmckayv Sep 10, 2026
364c2a6
test(desktop): make native fixtures portable and isolate their enviro…
davidmckayv Sep 10, 2026
6026fde
fix(desktop): confirm Unix descendants exit before stopping ancestors
davidmckayv Sep 10, 2026
cee491b
fix(desktop): stop Windows process trees without stale port sweeps
davidmckayv Sep 10, 2026
cf22437
fix(desktop): retry frozen dependency installs after partial failures
davidmckayv Sep 10, 2026
2f6869d
fix(desktop): stop supervisor before snapshotting computers
davidmckayv Sep 10, 2026
932d21a
fix(desktop): parse every Compose published port row
davidmckayv Sep 10, 2026
1a86b40
fix(desktop): require current API readiness before startup succeeds
davidmckayv Sep 10, 2026
b74ab27
style(desktop): remove blank-comment trailing whitespace
davidmckayv Sep 10, 2026
463de36
test(desktop): preserve PowerShell in restricted Windows fixtures
davidmckayv Sep 10, 2026
d4add44
test(desktop): serve readiness fixtures on both loopbacks
davidmckayv Sep 10, 2026
6191732
fix(desktop): resolve setup navigation from Tauri configuration
davidmckayv Sep 10, 2026
0e16787
test(desktop): name native fixture crates explicitly
davidmckayv Sep 10, 2026
5ef4199
test(desktop): use platform local origin for mock IPC
davidmckayv Sep 10, 2026
d89b8bc
ci(desktop): run library and shell regressions on every platform
davidmckayv Sep 10, 2026
07dbb75
fix(desktop): include IPv6 listeners in Windows port ownership
davidmckayv Sep 10, 2026
26819da
fix(desktop): dispatch Stop shutdown on a blocking worker
davidmckayv Sep 10, 2026
92360db
fix(desktop): retain unresolved legacy Windows PID evidence
davidmckayv Sep 10, 2026
b823ade
fix(desktop): preserve supervision through failed Start preflight
davidmckayv Sep 10, 2026
156bfc4
fix(desktop): clean up owned listener test fixture
davidmckayv Sep 10, 2026
5499c8d
fix(desktop): record Windows supervisor replacements before success
davidmckayv Sep 10, 2026
047fc55
fix(desktop): retain container ownership across failed Start retries
davidmckayv Sep 10, 2026
6d4cd41
fix(desktop): attribute empty answers to the selected endpoint
davidmckayv Sep 10, 2026
47ff912
fix(desktop): quiesce Unix launchers before descendant cleanup
davidmckayv Sep 10, 2026
824e228
fix(desktop): retain runtime affinity for container cleanup
davidmckayv Sep 10, 2026
f75ebb6
test(desktop): cover unavailable-engine shutdown recovery
davidmckayv Sep 11, 2026
988d564
fix(desktop): retain recovery until the owned run is restored
davidmckayv Sep 11, 2026
c6615e9
test: preserve CI test stderr before exit
davidmckayv Sep 11, 2026
4bbf884
test: keep CI stderr regression deterministic
davidmckayv Sep 11, 2026
880dc86
test: fix desktop ci fixture portability
davidmckayv Sep 11, 2026
42faeed
test: run ChatGPT token writer as host user
davidmckayv Sep 11, 2026
f058291
test: fix inline podman runtime fixture
davidmckayv Sep 11, 2026
a4b3c52
test: bind plugin audit JSON filters
davidmckayv Sep 11, 2026
7dabc51
test: stop channel new mock leaks
davidmckayv Sep 11, 2026
ca054ea
ci: install desktop deps before root tests
davidmckayv Sep 11, 2026
0b729ec
chore: integrate current main for CI validation
davidmckayv Sep 11, 2026
d288cbc
fix: retain menu stop failures through setup navigation
davidmckayv Sep 11, 2026
5ef6d20
test: repair merged plugin OAuth fixtures
davidmckayv Sep 11, 2026
15b2ba3
fix: preserve ChatGPT token store ownership on refresh
davidmckayv Sep 11, 2026
496a31e
fix: retain quit cleanup notice for setup recovery
davidmckayv Sep 11, 2026
b4491f8
test(desktop): model local Podman fixture affinity
davidmckayv Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ OPENAI_API_KEY=
#
# OPENAI_BASE_URL=

# Optional. Leave empty unless containers need a different route to the same compatible endpoint,
# such as a locally hosted model whose host URL is localhost but whose Compose-network URL is a
# service name. Empty means containers use OPENAI_BASE_URL too.
# OPENAI_CONTAINER_BASE_URL=

# The same for the other two providers, under the names the API server already reads. They are
# different APIs rather than different URLs for this one, so each has its own.
# ANTHROPIC_BASE_URL=
Expand Down
20 changes: 19 additions & 1 deletion .github/published-images.json
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
["agent-computer", "supervisor", "agent-bot", "agent-langgraph", "server"]
[
"agent-computer",
"supervisor",
"agent-bot",
"agent-langgraph",
"server",
"agent-crewai",
"agent-llamaindex",
"agent-agno",
"agent-langgraph-agui",
"agent-adk",
"agent-pydantic-ai",
"agent-microsoft",
"agent-claude-sdk",
"agent-strands",
"agent-ag2",
"agent-langroid",
"agent-mastra"
]
43 changes: 42 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ jobs:
# Bot's own tree and not in the root one.
- run: bun install --frozen-lockfile
working-directory: agent-langgraph
# Same for the Mastra Bot: root test discovery imports its receiver tests, which load Mastra
# from that Bot's own dependency tree.
- run: bun install
working-directory: agent-mastra
# Same for the desktop app: root test discovery imports its React tests, whose JSX runtime is
# pinned by the desktop lockfile rather than the root one.
- run: bun install --frozen-lockfile
working-directory: desktop
# Not the db:migrate script: that one loads ../.env, which does not exist in CI. DATABASE_URL
# comes from the job env instead, which drizzle.config.ts already reads.
- run: bunx drizzle-kit migrate --config=drizzle.config.ts
Expand All @@ -223,6 +231,39 @@ jobs:
# files before their tests are registered.
- run: bun run test:ci

python-harness:
name: python harness regressions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.14
- name: CrewAI provider-boundary regression
run: |
set -euo pipefail
python -m venv .venv-crewai
. .venv-crewai/bin/activate
python -m pip install --requirement agent-crewai/requirements.txt --requirement agent-crewai/requirements-test.txt
python -m pytest agent-crewai/tests -q
- name: LangGraph AG-UI provider-boundary regressions
run: |
set -euo pipefail
python -m venv .venv-langgraph-agui
. .venv-langgraph-agui/bin/activate
python -m pip install --requirement agent-langgraph-agui/requirements.txt --requirement agent-langgraph-agui/requirements-test.txt
python -m pytest agent-langgraph-agui/tests -q
- run: bun install --frozen-lockfile
- run: bun test tests/compose.test.ts
- run: docker compose --env-file /dev/null --profile harness config --format json >/dev/null
env:
PICKED_HARNESS_IMAGE: openbot-agent-langgraph-agui:test

build:
name: build
runs-on: ubuntu-latest
Expand Down Expand Up @@ -414,7 +455,7 @@ jobs:
name: verify
runs-on: ubuntu-latest
if: always()
needs: [static, deployables, chart, test, build, migrations, image, component-dockerfiles]
needs: [static, deployables, chart, test, python-harness, build, migrations, image, component-dockerfiles]
steps:
- name: Require every check
env:
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Desktop

# The shell is the one thing here that cannot be proved by running it on Linux: it is a macOS app, a
# Windows app and a Linux app built from one tree, and the ways they differ are exactly the ways
# this fails. So it builds on all three, on every change to it.
# this fails. So it tests and builds on all three, on every change to it.
on:
pull_request:
paths: ["desktop/**", ".github/workflows/desktop.yml"]
Expand All @@ -19,9 +19,7 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
# Fast, and the only job that runs the assertions about what the shell writes into `.env` and
# which socket it names. Those are the parts that carry what the platforms taught us, and they are
# plain Rust: no window, no engine, no waiting.
# Fast formatting and lint checks. Rust regression tests run once per platform below.
core:
name: core
runs-on: ubuntu-latest
Expand All @@ -44,8 +42,6 @@ jobs:
working-directory: desktop/src-tauri
- run: cargo clippy --all-targets -- -D warnings
working-directory: desktop/src-tauri
- run: cargo test --lib
working-directory: desktop/src-tauri

# The three artifacts. Not `bundle`, which signs and notarizes: that is S7 and needs certificates
# this workflow deliberately does not hold. This proves the tree builds into an app on each
Expand Down Expand Up @@ -95,6 +91,11 @@ jobs:
# which a compile would miss.
- run: bun run tauri build
working-directory: desktop
# Frontend assets and platform dependencies are ready after the packaged build.
# Include main.rs regressions as well as lib.rs; ignored live tests remain opt-in.
- name: Rust regression tests
run: cargo test --locked --lib --bins
working-directory: desktop/src-tauri
# Keep what was built. Without this the only way to try an installer is to build one on
# the machine you are trying it on, which is not what anybody installs.
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
19 changes: 19 additions & 0 deletions agent-adk/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Google ADK, as a Bot. Python rather than Bun because that is what the integration is published in,
# and the protocol is the only thing a Bot has to share with the others.
FROM python:3.12-slim

WORKDIR /app

# Dependencies before source, so editing the Bot does not re-resolve the framework.
COPY agent-adk/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY agent-adk/src ./src

ENV PORT=4208
EXPOSE 4208
# 0.0.0.0, not `::`. uvicorn binds `::` as IPv6-only, with no v4-mapped addresses, so a container
# started that way refuses 127.0.0.1: the Compose healthcheck never passes and the server cannot
# reach the Bot. Measured, not assumed. Inside a container this is the container's own namespace,
# and Compose is what decides which host addresses it is published on.
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "4208"]
6 changes: 6 additions & 0 deletions agent-adk/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ag-ui-adk
google-adk
litellm
fastapi
python-multipart
uvicorn[standard]
54 changes: 54 additions & 0 deletions agent-adk/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Google ADK as a Bot, through `ag_ui_adk`, which AG-UI maintains.

ADK is Gemini-first and model-agnostic after that, so the provider stays the person's choice: ADK
reads LiteLLM model strings, and OpenBot writes the one it was told.
"""

import os

from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm

TOKEN_HEADER = "x-openbot-agent-token"


def _model_id() -> str:
provider = (os.environ.get("BOT_PROVIDER") or "openai").strip()
model = (os.environ.get("BOT_MODEL") or "gpt-4o-mini").strip()
return model if "/" in model else f"{provider}/{model}"


app = FastAPI()


@app.middleware("http")
async def refuse_without_the_server_token(request: Request, call_next):
if request.url.path != "/health":
expected = (os.environ.get("MANAGED_AGENT_TOKEN") or "").strip()
offered = (request.headers.get(TOKEN_HEADER) or "").strip()
if not expected or offered != expected:
return JSONResponse({"error": "unauthorised"}, status_code=401)
return await call_next(request)


@app.get("/health")
async def health():
return {"ok": True, "harness": "google-adk"}


add_adk_fastapi_endpoint(
app,
ADKAgent(
adk_agent=Agent(
name="openbot",
model=LiteLlm(model=_model_id()),
instruction="Answer the question you are asked, briefly and correctly.",
),
app_name="openbot",
user_id="openbot",
),
path="/",
)
19 changes: 19 additions & 0 deletions agent-ag2/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# AG2, as a Bot. Python rather than Bun because that is what the integration is published in,
# and the protocol is the only thing a Bot has to share with the others.
FROM python:3.12-slim

WORKDIR /app

# Dependencies before source, so editing the Bot does not re-resolve the framework.
COPY agent-ag2/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY agent-ag2/src ./src

ENV PORT=4210
EXPOSE 4210
# 0.0.0.0, not `::`. uvicorn binds `::` as IPv6-only, with no v4-mapped addresses, so a container
# started that way refuses 127.0.0.1: the Compose healthcheck never passes and the server cannot
# reach the Bot. Measured, not assumed. Inside a container this is the container's own namespace,
# and Compose is what decides which host addresses it is published on.
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "4210"]
4 changes: 4 additions & 0 deletions agent-ag2/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ag2[ag-ui,openai]
fastapi
python-multipart
uvicorn[standard]
39 changes: 39 additions & 0 deletions agent-ag2/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""AG2 as a Bot. AG-UI is an extra in AG2's own package, so `ag2[ag-ui]` is the dependency."""

import os

from ag2 import Agent
from ag2.ag_ui import AGUIStream
from ag2.config import OpenAIConfig
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

TOKEN_HEADER = "x-openbot-agent-token"

agent = Agent(
name="openbot",
prompt="Answer the question you are asked, briefly and correctly.",
config=OpenAIConfig(model=(os.environ.get("BOT_MODEL") or "gpt-4o-mini").strip()),
)
stream = AGUIStream(agent)

app = FastAPI()


@app.middleware("http")
async def refuse_without_the_server_token(request: Request, call_next):
if request.url.path != "/health":
expected = (os.environ.get("MANAGED_AGENT_TOKEN") or "").strip()
offered = (request.headers.get(TOKEN_HEADER) or "").strip()
if not expected or offered != expected:
return JSONResponse({"error": "unauthorised"}, status_code=401)
return await call_next(request)


@app.get("/health")
async def health():
return {"ok": True, "harness": "ag2"}


# `build_asgi` rather than a helper: AG2 hands back a plain ASGI app to mount.
app.mount("/", stream.build_asgi())
19 changes: 19 additions & 0 deletions agent-agno/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Agno, as a Bot. Python rather than Bun because that is what the integration is published in,
# and the protocol is the only thing a Bot has to share with the others.
FROM python:3.12-slim

WORKDIR /app

# Dependencies before source, so editing the Bot does not re-resolve the framework.
COPY agent-agno/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY agent-agno/src ./src

ENV PORT=4203
EXPOSE 4203
# 0.0.0.0, not `::`. uvicorn binds `::` as IPv6-only, with no v4-mapped addresses, so a container
# started that way refuses 127.0.0.1: the Compose healthcheck never passes and the server cannot
# reach the Bot. Measured, not assumed. Inside a container this is the container's own namespace,
# and Compose is what decides which host addresses it is published on.
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "4203"]
5 changes: 5 additions & 0 deletions agent-agno/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
agno[agui]
litellm
fastapi
python-multipart
uvicorn[standard]
59 changes: 59 additions & 0 deletions agent-agno/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Agno as a Bot.

The AG-UI support is an extra in Agno's own package rather than a separate bridge, so `agno[agui]`
is the whole dependency and `AGUIApp` is the whole integration. Nothing of the protocol is written
here, which is the rule.
"""

import os

from agno.agent import Agent
from agno.db.in_memory import InMemoryDb
from agno.models.litellm import LiteLLM
from agno.os import AgentOS
from agno.os.interfaces.agui import AGUI
from fastapi import Request
from fastapi.responses import JSONResponse

TOKEN_HEADER = "x-openbot-agent-token"


def _model_id() -> str:
"""`provider/model`, which is how litellm addresses one and how OpenBot stores the choice."""
provider = (os.environ.get("BOT_PROVIDER") or "openai").strip()
model = (os.environ.get("BOT_MODEL") or "gpt-5.5").strip()
return model if "/" in model else f"{provider}/{model}"


agent = Agent(
# In memory, because a Bot's history lives in OpenBot's database and not in the harness. Two
# places remembering the same conversation is how they come to disagree.
db=InMemoryDb(),
model=LiteLLM(id=_model_id()),
# No role, goal or backstory invented on somebody's behalf. A Bot answers the question it is
# asked, and anybody who wants a persona sets one in OpenBot where the rest of them live.
instructions="Answer the question you are asked, briefly and correctly.",
)

app = AgentOS(agents=[agent], interfaces=[AGUI(agent=agent)]).get_app()


@app.middleware("http")
async def refuse_without_the_server_token(request: Request, call_next):
"""Everything but `/health` carries the server's token.

`/health` is exempt because Compose polls it before any token exists, and a healthcheck that
authenticates is a container that never reports healthy.
"""
if request.url.path != "/health":
expected = (os.environ.get("MANAGED_AGENT_TOKEN") or "").strip()
offered = (request.headers.get(TOKEN_HEADER) or "").strip()
# Unset means unconfigured, not open.
if not expected or offered != expected:
return JSONResponse({"error": "unauthorised"}, status_code=401)
return await call_next(request)


@app.get("/health")
async def health():
return {"ok": True, "harness": "agno"}
Loading