oh-my-agent-web 0.7.0 → 1.0.2
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.
- package/README.en.md +394 -248
- package/README.md +387 -247
- package/dist/server/approval/rules.js +4 -16
- package/dist/server/approval/scope.js +3 -3
- package/dist/server/cli-config.js +3 -3
- package/dist/server/cli-info.js +9 -9
- package/dist/server/cli.js +108 -23
- package/dist/server/engine/builtin.js +64 -1
- package/dist/server/engine/catalog-probe.js +34 -0
- package/dist/server/engine/claude-map.js +296 -0
- package/dist/server/engine/claude-sessions.js +581 -0
- package/dist/server/engine/claude-transport.js +75 -0
- package/dist/server/engine/claude.js +414 -0
- package/dist/server/engine/cli-version.js +119 -0
- package/dist/server/engine/codex-map.js +19 -23
- package/dist/server/engine/codex-sessions.js +5 -5
- package/dist/server/engine/codex-subagents.js +349 -0
- package/dist/server/engine/codex.js +215 -2
- package/dist/server/engine/dsh-history.js +1 -1
- package/dist/server/engine/dsh-log.js +47 -36
- package/dist/server/engine/dsh-map.js +3 -5
- package/dist/server/engine/dsh-prompt-patch.js +48 -0
- package/dist/server/engine/dsh-sessions.js +10 -11
- package/dist/server/engine/dsh-transport.js +2 -2
- package/dist/server/engine/dsh.js +45 -2
- package/dist/server/engine/engine-versions.js +41 -0
- package/dist/server/engine/fake.js +38 -7
- package/dist/server/engine/model-registry-reload.js +1 -1
- package/dist/server/engine/opencode-map.js +2 -2
- package/dist/server/engine/opencode-projects.js +1 -1
- package/dist/server/engine/opencode-sessions.js +2 -2
- package/dist/server/engine/opencode.js +39 -1
- package/dist/server/engine/pi-events.js +4 -4
- package/dist/server/engine/pi-plugins.js +8 -6
- package/dist/server/engine/pi-sdk.js +179 -5
- package/dist/server/engine/pi-subagent-tool.js +2 -2
- package/dist/server/engine/pi-subagents.js +2 -2
- package/dist/server/engine/pi-transcript.js +1 -1
- package/dist/server/engine/registry.js +12 -2
- package/dist/server/engine/suggestion-guidance.js +22 -9
- package/dist/server/engine/wiring.js +57 -3
- package/dist/server/files/content-search.js +187 -0
- package/dist/server/files/file-search.js +3 -3
- package/dist/server/files/file-service.js +33 -15
- package/dist/server/files/files-routes.js +68 -7
- package/dist/server/files/git-info.js +51 -11
- package/dist/server/files/path-resolve.js +176 -0
- package/dist/server/files/pick-dir-routes.js +93 -0
- package/dist/server/files/pick-path-routes.js +126 -0
- package/dist/server/http/auth-routes.js +71 -4
- package/dist/server/http/auth.js +48 -30
- package/dist/server/http/aux-routes.js +20 -4
- package/dist/server/http/file-headers.js +3 -3
- package/dist/server/http/health-and-static.js +1 -1
- package/dist/server/http/live-routes.js +4 -4
- package/dist/server/http/login-page.js +128 -1
- package/dist/server/http/password-store.js +31 -0
- package/dist/server/index.js +93 -11
- package/dist/server/markers/actions.js +8 -8
- package/dist/server/mcp/codex-mcp-store.js +190 -0
- package/dist/server/mcp/json-mcp-store.js +276 -0
- package/dist/server/mcp/mcp-auth.js +1 -1
- package/dist/server/mcp/mcp-command.js +0 -2
- package/dist/server/mcp/mcp-engine-shared.js +112 -0
- package/dist/server/mcp/mcp-import.js +4 -5
- package/dist/server/mcp/mcp-market.js +2 -3
- package/dist/server/mcp/mcp-routes.js +4 -3
- package/dist/server/mcp/none-mcp-store.js +27 -0
- package/dist/server/mcp/pi-mcp-config.js +1 -1
- package/dist/server/plugins/engine-plugin-stores.js +265 -0
- package/dist/server/plugins/plugin-routes.js +4 -3
- package/dist/server/protocol-parse.js +52 -4
- package/dist/server/protocol.js +0 -1
- package/dist/server/providers/catalog-writes.js +1 -1
- package/dist/server/providers/catalog.js +2 -2
- package/dist/server/providers/codex-models.js +1 -1
- package/dist/server/providers/codex-test.js +1 -1
- package/dist/server/providers/enabled-models.js +1 -11
- package/dist/server/providers/import-routes.js +2 -2
- package/dist/server/providers/probe-routes.js +26 -0
- package/dist/server/providers/provider-handlers.js +3 -3
- package/dist/server/providers/provider-pool.js +2 -2
- package/dist/server/providers/provider-store.js +5 -2
- package/dist/server/providers/subscription-routes.js +4 -2
- package/dist/server/providers/validate.js +13 -14
- package/dist/server/push/push-routes.js +32 -3
- package/dist/server/push/push.js +43 -9
- package/dist/server/session/client-view.js +2 -2
- package/dist/server/session/close-ephemeral.js +23 -0
- package/dist/server/session/conversation-create.js +31 -9
- package/dist/server/session/delete-session.js +25 -14
- package/dist/server/session/engine-switch.js +12 -5
- package/dist/server/session/fork-session.js +38 -0
- package/dist/server/session/lock.js +4 -4
- package/dist/server/session/model-controller.js +14 -2
- package/dist/server/session/move-session.js +40 -0
- package/dist/server/session/persist-ephemeral.js +48 -0
- package/dist/server/session/pi-opener.js +2 -2
- package/dist/server/session/pi-refresh.js +1 -1
- package/dist/server/session/pi-sessions-provider.js +2 -2
- package/dist/server/session/pi-sessions.js +107 -18
- package/dist/server/session/runtime.js +144 -9
- package/dist/server/session/session-stats.js +2 -2
- package/dist/server/session/settings.js +45 -49
- package/dist/server/session/subagents.js +4 -1
- package/dist/server/session/suggest-title.js +33 -0
- package/dist/server/session/title-prompt.js +126 -0
- package/dist/server/session/turn-finish.js +2 -2
- package/dist/server/session/turn-queue.js +5 -5
- package/dist/server/session/turn-watchdog.js +2 -2
- package/dist/server/skills/skill-install.js +3 -5
- package/dist/server/skills/skill-store.js +3 -3
- package/dist/server/skills/skillhub.js +3 -4
- package/dist/server/snapshot/messages.js +2 -8
- package/dist/server/snapshot/sender.js +1 -1
- package/dist/server/snapshot/state.js +3 -5
- package/dist/server/subagents/profile-store.js +11 -9
- package/dist/server/terminal/terminal-session.js +9 -9
- package/dist/server/uploads/upload-routes.js +1 -1
- package/dist/server/uploads/upload-store.js +4 -6
- package/dist/server/util/env.js +27 -21
- package/dist/server/util/ids.js +1 -1
- package/dist/server/util/json-file.js +38 -0
- package/dist/server/util/log-file.js +3 -3
- package/dist/server/util/log.js +4 -4
- package/dist/server/util/origin.js +5 -24
- package/dist/server/util/paths.js +25 -3
- package/dist/server/util/pricing-index.js +2 -6
- package/dist/server/util/pricing.js +10 -10
- package/dist/server/util/spawn-cli.js +2 -2
- package/dist/server/util/upstream-version.js +10 -12
- package/dist/server/util/version.js +2 -2
- package/dist/server/web-proxy/proxy-routes.js +167 -0
- package/dist/server/web-proxy/proxy-url.js +60 -0
- package/dist/server/web-proxy/rewrite.js +84 -0
- package/dist/server/ws/handle-message.js +21 -2
- package/package.json +13 -14
- package/scripts/prune-prebuilds.mjs +1 -1
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_abnfDiagram-WEYOIA3C-Dq-2fRb4.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_architectureDiagram-ZHVYKT53-Dh5CEs4k.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_c4Diagram-XDPPPE54-Cb19QmmE.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_cynefinDiagram-WF24UDRP-COk-IL9O.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-CBK3MWTC-Gp_0nfEJ.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-ODIL2UCW-rzPf_9IN.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-PFBEJUXE-B5EnLWwl.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_diagram-TYUNFSNR-DVpFKFwC.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_ebnfDiagram-V4P3TTPT-CDL1qiPY.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_ishikawaDiagram-HPEHV2GE-CSkoONzp.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_mindmap-definition-6OY57UG3-B9sdVB6_.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_pegDiagram-ECIUJNBX-B6P7baCF.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_railroadDiagram-Y72NRBL7-W_a8Vy2l.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_swimlanes-B3ENRKFQ-DvGif-RR.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_swimlanesDiagram-AYQRV4AK-D0gFG_EI.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_usecaseDiagram-WPOLBNNX-BjgUBJiR.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_vennDiagram-Q3Y3IDCW-DnVuWTpF.js +1 -0
- package/web/dist/assets/_oh-my-agent-web-mermaid-pruned_chunk_wardleyDiagram-IVAIDKWA-B2vDAqpl.js +1 -0
- package/web/dist/assets/{arc-BTAvbR16.js → arc-Df9SI9yh.js} +1 -1
- package/web/dist/assets/{architecture-WOLXFQ4H-fewLD5_7.js → architecture-WOLXFQ4H-iO49E8Y1.js} +1 -1
- package/web/dist/assets/{blockDiagram-RJAE7QA3-ClmgyxZl.js → blockDiagram-RJAE7QA3-D8d1ukIs.js} +1 -1
- package/web/dist/assets/channel-C2-OT56h.js +1 -0
- package/web/dist/assets/{chunk-55XCU76K-DdC5EhZG.js → chunk-55XCU76K-C5wOvqDb.js} +1 -1
- package/web/dist/assets/{chunk-7S6XSTFO-CgToWHK6.js → chunk-7S6XSTFO-WIrWcDbG.js} +1 -1
- package/web/dist/assets/{chunk-AQDTSKZB-D-rQMnp7.js → chunk-AQDTSKZB-OkzYqFsw.js} +1 -1
- package/web/dist/assets/{chunk-DSNLSHJZ-cuZoTGMH.js → chunk-DSNLSHJZ-CHEA9kYd.js} +2 -2
- package/web/dist/assets/{chunk-HNE4Q36P-CiKr9iSN.js → chunk-HNE4Q36P-CPsq34CI.js} +1 -1
- package/web/dist/assets/{chunk-VQ5W62QI-DbTfXAAT.js → chunk-VQ5W62QI-CamPnEuF.js} +1 -1
- package/web/dist/assets/{chunk-WQQL4CDK-DHanHfB5.js → chunk-WQQL4CDK-gNypBVAM.js} +1 -1
- package/web/dist/assets/{chunk-ZAUX2LTX-SrjFXpy2.js → chunk-ZAUX2LTX--4WyRBRV.js} +1 -1
- package/web/dist/assets/{chunk-ZCHMQSOR-7Wy8xXQ5.js → chunk-ZCHMQSOR-umv3Lkpn.js} +1 -1
- package/web/dist/assets/{classDiagram-v2-4MYWR3UA-CBe5ZDvZ.js → classDiagram-v2-4MYWR3UA-C1XldpO1.js} +1 -1
- package/web/dist/assets/{cose-bilkent-JH36ORCC-Dljdyvhw.js → cose-bilkent-JH36ORCC-BvugZzFU.js} +1 -1
- package/web/dist/assets/{cynefin-EF2NZ3EQ-CcZU7GFP.js → cynefin-EF2NZ3EQ-6qXB70s4.js} +1 -1
- package/web/dist/assets/{dagre-NK4GIZVX-Bq_6y8qp.js → dagre-NK4GIZVX-DDdlABYw.js} +1 -1
- package/web/dist/assets/{diagram-I5XIIV2D-C2lnnYVG.js → diagram-I5XIIV2D-T8oWy5CY.js} +1 -1
- package/web/dist/assets/{diagram-RJA3I4VV-Bqf8Z6wJ.js → diagram-RJA3I4VV-CkdHTtfV.js} +1 -1
- package/web/dist/assets/{elk-QONTBCTQ-Cdzq_cJ5.js → elk-QONTBCTQ-BiEUbJJX.js} +1 -1
- package/web/dist/assets/{erDiagram-KYQIGQAA-ZJLCjPFC.js → erDiagram-KYQIGQAA-q3WwhyzH.js} +1 -1
- package/web/dist/assets/{eventmodeling-K75KTNOO-DHqeIpes.js → eventmodeling-K75KTNOO-BO5gW_NC.js} +1 -1
- package/web/dist/assets/{flowDiagram-IUGLLWBU-AVgYvXKN.js → flowDiagram-IUGLLWBU-DubjP6UK.js} +1 -1
- package/web/dist/assets/{ganttDiagram-R7GPNTJY-CR1SG1M7.js → ganttDiagram-R7GPNTJY-lKNRH8CI.js} +1 -1
- package/web/dist/assets/{gitGraph-VSP46ZUC-CIZQPK0R.js → gitGraph-VSP46ZUC-Cwlv3omT.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-PDYL7XHY-BhOCWEh6.js → gitGraphDiagram-PDYL7XHY-Bo9GpFvW.js} +1 -1
- package/web/dist/assets/index-CeYhxqkk.js +113 -0
- package/web/dist/assets/index-GJgJwZ23.css +1 -0
- package/web/dist/assets/{info-OHQRW6UA-C2wuRxeQ.js → info-OHQRW6UA-g3MbTRmN.js} +1 -1
- package/web/dist/assets/{infoDiagram-MVDRKAX5-BP5doAB5.js → infoDiagram-MVDRKAX5-CmILYLoB.js} +1 -1
- package/web/dist/assets/{journeyDiagram-BOSHW7O7-BcIDRTPS.js → journeyDiagram-BOSHW7O7-Av8T0U1C.js} +1 -1
- package/web/dist/assets/{kanban-definition-FNSA4HC5-CRH_bcoT.js → kanban-definition-FNSA4HC5-B9NyWQYN.js} +1 -1
- package/web/dist/assets/{line-iA4GPA_S.js → line-BUrll1My.js} +1 -1
- package/web/dist/assets/{linear-BGUKwkTH.js → linear-DjET0phX.js} +1 -1
- package/web/dist/assets/{math-DgNW_bVP.js → math-BJAjkhlu.js} +1 -1
- package/web/dist/assets/{mermaid-parser.core-CsqmgpEv.js → mermaid-parser.core-CaTdkhkS.js} +3 -3
- package/web/dist/assets/{mermaid.core-C1yCGQK6.js → mermaid.core-Cktx937U.js} +4 -4
- package/web/dist/assets/{packet-JDAUHWVQ-2ggaoz2g.js → packet-JDAUHWVQ-DhG6l3PG.js} +1 -1
- package/web/dist/assets/{pie-XZMESJXO-h_yslQQs.js → pie-XZMESJXO-YPcOx7s0.js} +1 -1
- package/web/dist/assets/{pieDiagram-GNMPY74T-6-JZMFyk.js → pieDiagram-GNMPY74T-DesiZKUl.js} +1 -1
- package/web/dist/assets/{quadrantDiagram-D57K4MC3-K5r1HOgL.js → quadrantDiagram-D57K4MC3-Cn1kBVgu.js} +1 -1
- package/web/dist/assets/{radar-ABXABTNO-6fOJGGgq.js → radar-ABXABTNO-CtuRfYSz.js} +1 -1
- package/web/dist/assets/{railroad-I3PHUGI6-B_gUgQ3d.js → railroad-I3PHUGI6-D5Gnyy0R.js} +1 -1
- package/web/dist/assets/{railroad-abnf-LNEFI6M7-CJ_eqiXZ.js → railroad-abnf-LNEFI6M7-Kw4pmJEm.js} +1 -1
- package/web/dist/assets/{railroad-ebnf-DWYD2UWJ-BTsgjLTU.js → railroad-ebnf-DWYD2UWJ-D8Mk5dIe.js} +1 -1
- package/web/dist/assets/{railroad-peg-JR7BVNR7-D91uiLln.js → railroad-peg-JR7BVNR7-R5Jwzs8F.js} +1 -1
- package/web/dist/assets/{requirementDiagram-EQYSW5RA-uapnV_OO.js → requirementDiagram-EQYSW5RA-B9RDq-cL.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-SY24JHO5-BQsbFgUb.js → sankeyDiagram-SY24JHO5-DoEatOm6.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-BLEHNHQU-iRoSYX_e.js → sequenceDiagram-BLEHNHQU-DGE5Z9lT.js} +1 -1
- package/web/dist/assets/{src-BBrKcs9r.js → src-BnEL7pZw.js} +1 -1
- package/web/dist/assets/{stateDiagram-v2-A6IESKWZ-Bzj9z5KH.js → stateDiagram-v2-A6IESKWZ-_vn8W-k_.js} +1 -1
- package/web/dist/assets/{timeline-definition-JXYKGLGB-DLUUuJX0.js → timeline-definition-JXYKGLGB-BaSLTtgR.js} +1 -1
- package/web/dist/assets/{treeView-D4JQ5SDB-CphIQ3n5.js → treeView-D4JQ5SDB-DZElyFgL.js} +1 -1
- package/web/dist/assets/{treemap-SAJKECNS-DqU3insw.js → treemap-SAJKECNS-DWDO4K4G.js} +1 -1
- package/web/dist/assets/{wardley-7MLQ67FV-Ch7d8cmC.js → wardley-7MLQ67FV-DTOUsk6Q.js} +1 -1
- package/web/dist/assets/{xychartDiagram-4URNHDU4-DdxpWBeM.js → xychartDiagram-4URNHDU4-DiaCfgAB.js} +1 -1
- package/web/dist/index.html +2 -2
- package/docs/screenshots/01-chat.png +0 -0
- package/docs/screenshots/02-answer.png +0 -0
- package/docs/screenshots/03-files-diff.png +0 -0
- package/docs/screenshots/04-terminal.png +0 -0
- package/docs/screenshots/05-models.png +0 -0
- package/docs/screenshots/06-skills.png +0 -0
- package/docs/screenshots/07-skills-hub.png +0 -0
- package/docs/screenshots/08-mcp.png +0 -0
- package/docs/screenshots/09-subagents.png +0 -0
- package/docs/screenshots/10-settings.png +0 -0
- package/docs/screenshots/11-plugins.png +0 -0
- package/docs/screenshots/12-voice.png +0 -0
- package/docs/screenshots/13-push.png +0 -0
- package/docs/screenshots/README.md +0 -45
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_abnfDiagram-WEYOIA3C-CvNbnJ75.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_architectureDiagram-ZHVYKT53-T7NZZ4ao.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_c4Diagram-XDPPPE54-ByuAPg39.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_cynefinDiagram-WF24UDRP-BY5DHttT.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-CBK3MWTC-D7ZYyrF7.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-ODIL2UCW-C6kcOZFc.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-PFBEJUXE-CzFPFq0D.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_diagram-TYUNFSNR-B4G4T8SL.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_ebnfDiagram-V4P3TTPT-BkQ4xwD0.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_ishikawaDiagram-HPEHV2GE-52xqckJv.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_mindmap-definition-6OY57UG3-7cQksbFn.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_pegDiagram-ECIUJNBX-udgtBpwv.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_railroadDiagram-Y72NRBL7-Cd2dcQWz.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_swimlanes-B3ENRKFQ-p34pL1Yk.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_swimlanesDiagram-AYQRV4AK-BslfPs4r.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_usecaseDiagram-WPOLBNNX-DJZoN9Xk.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_vennDiagram-Q3Y3IDCW-DPXo67cZ.js +0 -1
- package/web/dist/assets/_omaw-mermaid-pruned_chunk_wardleyDiagram-IVAIDKWA-BE6ukwkg.js +0 -1
- package/web/dist/assets/channel-DfaYIFFE.js +0 -1
- package/web/dist/assets/index-CZQjJbRg.js +0 -104
- package/web/dist/assets/index-ChDUWKZX.css +0 -1
- /package/web/dist/assets/{_omaw-mermaid-pruned_katex_katex-Zojedrce.js → _oh-my-agent-web-mermaid-pruned_katex_katex-Zojedrce.js} +0 -0
package/README.en.md
CHANGED
|
@@ -2,78 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
[中文](README.md) · **English**
|
|
4
4
|
|
|
5
|
-
One line: **an external control surface for the agent you're already running.** The engine keeps running on your own machine;
|
|
5
|
+
One line: **an external control surface for the agent you're already running.** The engine keeps running on your own machine; the web page is where you watch it work, manage its tools and models, cut in to correct it whenever you like, and — when the moment comes — read files, open a terminal, or highlight a passage and ask for a change.
|
|
6
6
|
|
|
7
|
-
Single user, loopback only, and the engine's own on-disk files are the source of truth for
|
|
7
|
+
Single user, loopback only, and **the engine's own on-disk files are always the source of truth for a conversation** — no database, no account system, no second copy of the session in our own store. One `oh-my-agent-web` process is one person's workbench.
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
> Every screenshot below is the real UI of this repo (the 0.8.0 build) — pi engine + DeepSeek, working on a small `demo-app` project.
|
|
12
|
+
> Directories, commands, the `+6 −1` diff, tokens and cost all come from that actual run — no collages, no mockups.
|
|
13
|
+
> What each shot shows, how it was taken and how it was compressed is in [`docs/screenshots/README.md`](docs/screenshots/README.md).
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Install
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Requires **Node.js ≥ 22.19** and **npm ≥ 9**; macOS / Linux / Windows all work. You end up with an `oh-my-agent-web` command (short aliases: `aw`, `agent-web` — all equivalent).
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|---|---|---|
|
|
23
|
-
| **Conversation** | center | Streaming text + collapsible thinking blocks + tool cards (arguments / full command / output / duration / ok or failed) + a "N steps" process block + a usage footer (tokens / cache / cost) + chips for changed files |
|
|
24
|
-
| **Steer & queue** | composer | Cut in mid-turn and the next message takes effect immediately; queued messages can be retracted; sent messages fold into the process block |
|
|
25
|
-
| **Engines** | top bar picker | pi / Codex / DeepSeek Harness / opencode each with its native loop (not one prompt in four costumes); every session remembers its engine, model and thinking level |
|
|
26
|
-
| **Subagents** | top bar "subagents" + the strip under the conversation | The main agent gets an `Agent` tool and can run several **real sessions** in parallel; run cards show status / duration / tool count / tokens / cost, expand in place for the result, and can be stopped individually. The panel manages templates: tool allowlist, model, thinking level, max turns, concurrency (1–12) |
|
|
27
|
-
| **Models & providers** | top bar "models" | The 41 providers in pi's official catalog work **with just a key** — no base URLs, no hand-copied model IDs. Custom providers expose the api shape (openai-completions / responses / anthropic-messages / codex / typesafe), base URL and custom headers; tick models, batch-test speed, pull the list from `/models`, save a whitelist. **Keys never leave the server** (only the last four digits come back) |
|
|
28
|
-
| **Skills** | top bar "skills" | Installed list with enable/disable and a reader for `SKILL.md` plus the skill's files; **Skill Hub** search and one-click install (200k+ index), install from a Git repo, or create by hand. Enabling means renaming `SKILL.md` — there is no second state file |
|
|
29
|
-
| **MCP** | top bar "MCP" | Edit both `mcp.json` files (global and project; a project entry with the same name wins), enable/disable, pick an exposure level (codemode / deferred / direct / hidden), **test the connection** (real handshake + tool list), OAuth login, browse a marketplace |
|
|
30
|
-
| **Plugins** | top bar "plugins" | pi packages (npm / git / local dir) with four states (loaded / installed / missing / disabled), per-package disabling, plus loose single-file extensions; state comes from pi's own resolution — only install/uninstall/update touch the disk |
|
|
31
|
-
| **File manager** | sidebar "files" | Directory tree (switchable root), search by name, show hidden files, collapse all, upload and download, reveal in Finder; uncommitted changes are dotted in the tree |
|
|
32
|
-
| **File viewer** | right pane (multi-tab) | Markdown / source with line numbers / images / PDF / audio-video streams; select lines and "add to conversation" to use them as context; full screen and draggable width |
|
|
33
|
-
| **Diff** | "diff" at the top of the viewer | Compared against HEAD: a `+285 −78` summary, line-level red/green highlighting, switch between diff and full file; opening from a "changed files" chip lands straight on the diff |
|
|
34
|
-
| **git** | top of the files pane | Branch chip (click to switch local branches, confirms first on a dirty tree), `M` / `U` / `D` markers after filenames |
|
|
35
|
-
| **Terminal** | files pane `>_`, right-pane tab | A real PTY (`node-pty` + xterm.js) sharing the session's cwd, with an optional initial command; on Linux it tells you exactly which build tools are missing |
|
|
36
|
-
| **Push** | top bar "push" | Web Push subscriptions (VAPID); one notification per finished turn — title is the project, body the session, with ❌ for failures and ⏹ for interrupts. Multiple devices, test push, clear all; needs https or localhost |
|
|
37
|
-
| **Voice** | top bar "voice" | Four event sounds (start / finish / error / waiting for approval) with preview and volume; local TTS (the browser's own voices, no network) that can read the final reply, with speed and voice selection |
|
|
38
|
-
| **Settings** | top bar "settings" | Four pages: **UI** (which chunks appear in the top bar and status bar), **general** (saved phrases, etc.), **appearance** (chat font size ×4, content width ×4, six palettes: bright white, warm paper, mist, Tokyo night, mocha, nord), **language** (Chinese / English, applies instantly) |
|
|
39
|
-
| **Sessions** | sidebar | Grouped by directory into "projects"; pin, rename, archive (undoable), delete (renames to `.deleted-<timestamp>`, the file survives). A session *is* the engine's own file — identical to what the CLI shows |
|
|
40
|
-
| **Attachments** | composer | Drag-and-drop upload, `@` file mentions, pasted images; uploads land in the data dir, never in your project |
|
|
41
|
-
| **Mobile** | — | Responsive: the sidebar becomes a drawer, process blocks collapse to a caret, below 400px it switches to the phone layout |
|
|
42
|
-
|
|
43
|
-
> Every screenshot below comes from a **real, running instance** (taken on this project's own session) — nothing is mocked up.
|
|
44
|
-
|
|
45
|
-
---
|
|
21
|
+
### Install globally with npm (recommended)
|
|
46
22
|
|
|
47
|
-
|
|
23
|
+
```bash
|
|
24
|
+
npm -g install oh-my-agent-web
|
|
25
|
+
```
|
|
48
26
|
|
|
49
|
-
|
|
50
|
-
|---|---|
|
|
51
|
-
|  |  |
|
|
52
|
-
| **Answer**: markdown, tables, code highlighting, token and cost footer | **Diff**: against HEAD, line-level red/green |
|
|
53
|
-
|  |  |
|
|
54
|
-
| **Terminal**: a real PTY in the session's cwd | **Models**: the 41 built-ins need only a key; ticked models apply |
|
|
55
|
-
|  |  |
|
|
56
|
-
| **Skills**: installed list, toggles, and `SKILL.md` | **Skill Hub**: search by category, install in one click |
|
|
57
|
-
|  |  |
|
|
58
|
-
| **MCP**: global and project config, exposure, connection test | **Subagents**: who is running, results, templates and tool allowlists |
|
|
59
|
-
|  |  |
|
|
60
|
-
| **Settings → appearance**: font size, width, six palettes | **Plugins**: load state of pi packages, with toggles |
|
|
61
|
-
|
|
62
|
-
Two more: [voice (event sounds + local TTS)](docs/screenshots/12-voice.png), [push (subscriptions and devices)](docs/screenshots/13-push.png).
|
|
27
|
+
No version tag means the current release. To pin a version or use a mirror:
|
|
63
28
|
|
|
64
|
-
|
|
29
|
+
```bash
|
|
30
|
+
npm -g install oh-my-agent-web@latest
|
|
31
|
+
npm -g install oh-my-agent-web@<version> --registry=https://registry.npmmirror.com
|
|
32
|
+
```
|
|
65
33
|
|
|
66
|
-
|
|
34
|
+
You get three commands that all point at the same entry point: **`oh-my-agent-web`** (used throughout this README),
|
|
35
|
+
`aw` (the short alias you'll probably type), and `agent-web`.
|
|
67
36
|
|
|
68
|
-
|
|
37
|
+
Upgrade and uninstall:
|
|
69
38
|
|
|
70
39
|
```bash
|
|
71
|
-
|
|
72
|
-
npm
|
|
73
|
-
npm start # foreground; Ctrl-C to quit
|
|
40
|
+
oh-my-agent-web upgrade # same as npm -g install oh-my-agent-web@latest
|
|
41
|
+
npm -g uninstall oh-my-agent-web # uninstall; data in ~/.oh-my-agent-web is left alone
|
|
74
42
|
```
|
|
75
43
|
|
|
76
|
-
|
|
44
|
+
On Linux, `node-pty` (the embedded terminal) ships prebuilds only for macOS / Windows, so Linux compiles it in place: you need `make`, `g++` and `python3`. When those are missing, both the page and the install script say exactly what's missing — the terminal won't open until then.
|
|
77
45
|
|
|
78
46
|
### One-line install (never touches global npm)
|
|
79
47
|
|
|
@@ -89,294 +57,472 @@ Windows (PowerShell):
|
|
|
89
57
|
powershell -c "irm https://raw.githubusercontent.com/duzhenxun/oh-my-agent-web/main/scripts/install.ps1 | iex"
|
|
90
58
|
```
|
|
91
59
|
|
|
92
|
-
The script does four things: **finds a new enough Node** (
|
|
60
|
+
The script does four things: **finds a new enough Node** (downloads an official build into `~/.oh-my-agent-web/node` and checks its sha256 if needed), **`npm install -g --prefix ~/.oh-my-agent-web`** (never the system-wide prefix, no sudo), **links `aw` / `agent-web` / `oh-my-agent-web` into `~/.local/bin`** (patching PATH if necessary), and **smoke-tests once** (version string + whether `node-pty` can be required, i.e. whether the terminal will open).
|
|
93
61
|
|
|
94
|
-
|
|
95
|
-
|---|---|
|
|
96
|
-
| Version | `OMAW_VERSION=0.7.0` (or `--version 0.7.0`) |
|
|
97
|
-
| Install location | `OMAW_HOME=/opt/omaw` (or `--home /opt/omaw`) |
|
|
98
|
-
| Registry mirror | `OMAW_REGISTRY=https://registry.npmmirror.com` (or `--registry …`) |
|
|
99
|
-
| Leave PATH alone | `OMAW_NO_PATH=1` (or `--no-modify-path`) |
|
|
100
|
-
| Install build tools | `OMAW_BUILD_TOOLS=1` (or `--with-build-tools`) |
|
|
101
|
-
| Uninstall | `… \| sh -s -- --uninstall` (removes the install dir and symlink only, never your data dir) |
|
|
62
|
+
That `~/.oh-my-agent-web` is also the **data directory**: what gets installed (`node/`, `lib/`, `bin/`) sits next to your `settings.json`, `password`, `uploads/` and `logs/`.
|
|
102
63
|
|
|
103
|
-
|
|
64
|
+
| What you want to change | How (`sh` version; PowerShell uses env vars) |
|
|
65
|
+
|---|---|
|
|
66
|
+
| Version | `OH_MY_AGENT_WEB_VERSION=<version>` (or `--version <version>`) |
|
|
67
|
+
| Install elsewhere | `OH_MY_AGENT_WEB_HOME=/opt/oh-my-agent-web` (or `--home /opt/oh-my-agent-web`) |
|
|
68
|
+
| Registry mirror | `OH_MY_AGENT_WEB_REGISTRY=https://registry.npmmirror.com` (or `--registry …`) |
|
|
69
|
+
| Leave PATH alone | `OH_MY_AGENT_WEB_NO_PATH=1` (or `--no-modify-path`) |
|
|
70
|
+
| Install build tools | `OH_MY_AGENT_WEB_BUILD_TOOLS=1` (or `--with-build-tools`) |
|
|
71
|
+
| Uninstall | `… \| sh -s -- --uninstall` (removes only what was installed; `settings.json` / password / uploads / logs stay) |
|
|
104
72
|
|
|
105
|
-
|
|
73
|
+
---
|
|
106
74
|
|
|
107
|
-
|
|
75
|
+
## Commands
|
|
108
76
|
|
|
109
|
-
`oh-my-agent-web`
|
|
77
|
+
The three commands are completely equivalent; everything below is written as `oh-my-agent-web` (`aw` is its short alias).
|
|
110
78
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
79
|
+
| Command | What it does |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `oh-my-agent-web` | **Start (default)**: runs in the background and opens the browser, handing the terminal straight back; default workspace = current directory |
|
|
82
|
+
| `oh-my-agent-web start -f` | Run in the foreground, logs right in the terminal, `Ctrl-C` to quit |
|
|
83
|
+
| `oh-my-agent-web status` | pid / port / uptime / engine / session count / workspace |
|
|
84
|
+
| `oh-my-agent-web restart` | Stop then start (background by default; `-f` for foreground) |
|
|
85
|
+
| `oh-my-agent-web stop` | Stop the running instance (foreground or background — it reads the lock file in the data dir instead of guessing a port) |
|
|
86
|
+
| `oh-my-agent-web version` | Version string (`-v` / `--version` are synonyms) |
|
|
87
|
+
| `oh-my-agent-web upgrade` | Upgrade to the latest release (it runs `npm -g install oh-my-agent-web@latest`) |
|
|
88
|
+
| `oh-my-agent-web help` | Show help (`-h` / `--help` are synonyms) |
|
|
119
89
|
|
|
120
|
-
###
|
|
90
|
+
### Flags
|
|
121
91
|
|
|
122
92
|
| Flag | Env var | Default | Notes |
|
|
123
|
-
|
|
93
|
+
|---|---|---|---|
|
|
124
94
|
| `-p, --port` | `AGENT_WEB_PORT` | `25257` | Listen port |
|
|
125
|
-
| `-H, --host` | `AGENT_WEB_HOST` | `127.0.0.1` |
|
|
126
|
-
| `-P, --password` | `AGENT_WEB_PASSWORD` | none |
|
|
127
|
-
|
|
|
128
|
-
| `--
|
|
129
|
-
|
|
|
95
|
+
| `-H, --host` | `AGENT_WEB_HOST` | `127.0.0.1` | Listen address; only change it for remote access |
|
|
96
|
+
| `-P, --password` | `AGENT_WEB_PASSWORD` | none | Login password; unset = loopback only (a remote first visit asks you to set one) |
|
|
97
|
+
| `-f, --foreground` | — | off (background by default) | Foreground run, logs in the terminal; `-d` / `--detach` is the old spelling and now equals the default |
|
|
98
|
+
| `--no-open` | — | on | Don't open the browser |
|
|
99
|
+
| `--allow-host` | `AGENT_WEB_ALLOWED_HOSTS` | loopback only | Extra allowed hostnames / LAN IPs (repeatable or comma-separated) |
|
|
100
|
+
| `--data-dir` | `AGENT_WEB_DATA_DIR` | `~/.oh-my-agent-web` | Settings, password, uploads, logs and the lock file live here |
|
|
101
|
+
| — | `AGENT_WEB_CWD` | `process.cwd()` | Default workspace (before any session exists) |
|
|
130
102
|
| — | `AGENT_WEB_ENGINE` | `pi` | Default engine |
|
|
131
|
-
| — | `AGENT_WEB_APPROVAL_MODE` | `allow` | Default approval mode for new sessions;
|
|
132
|
-
| — | `AGENT_WEB_TURN_TIMEOUT_MS` | 20
|
|
103
|
+
| — | `AGENT_WEB_APPROVAL_MODE` | `allow` | Default approval mode for new sessions; `ask` confirms every tool call |
|
|
104
|
+
| — | `AGENT_WEB_TURN_TIMEOUT_MS` | 20 minutes | Per-turn watchdog timeout |
|
|
133
105
|
| — | `AGENT_WEB_LOG` | `info` | `debug` / `info` / `warn` / `error` |
|
|
134
106
|
|
|
135
|
-
|
|
107
|
+
### Common examples
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
oh-my-agent-web # background + open the page (the usual one)
|
|
111
|
+
oh-my-agent-web -f # foreground, logs in your face, Ctrl-C to quit
|
|
112
|
+
oh-my-agent-web -p 25258 # different port (when 25257 is taken)
|
|
113
|
+
oh-my-agent-web status && oh-my-agent-web restart # check, then restart
|
|
114
|
+
oh-my-agent-web stop # stop it (works for foreground and background)
|
|
115
|
+
oh-my-agent-web --data-dir ~/agent-web-data # different data directory
|
|
116
|
+
AGENT_WEB_CWD=~/code/my-proj oh-my-agent-web # set the default workspace
|
|
117
|
+
oh-my-agent-web -H 0.0.0.0 --allow-host agent.example.com # allow outside access (first visit asks you to set a password)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
> **Reaching it from your phone**: `oh-my-agent-web -H 0.0.0.0 --allow-host your.domain`. The first visit from the phone asks you to **set an access password** (stored as `password` in the data dir; after that you just log in). Reverse proxies / tunnels should pass `X-Forwarded-For` (origin checking looks at it).
|
|
121
|
+
>
|
|
122
|
+
> **Running `oh-my-agent-web` from your home directory** works, but home is an unsafe workspace (the file tree, search and the agent's cwd would be your whole home). In that case it falls back to `<data dir>/workspace` and prints a line about it; to point at a project use `AGENT_WEB_CWD=/path/to/project`.
|
|
123
|
+
|
|
124
|
+
Each engine also has its own escape hatches (all have defaults; you normally don't touch them): `AGENT_WEB_CODEX_BIN` / `_HOME`, `AGENT_WEB_DSH_BIN` / `_HOME` / `_MODEL` / `_PATCH`, `AGENT_WEB_OPENCODE_BIN` / `_ARGS` / `_MODEL`, `AGENT_WEB_CLAUDE_BIN` / `_ARGS` / `_MODEL` (it auto-detects `claude-code-acp` / `claude-agent-acp` and says so when neither is installed).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## What it is, what it isn't
|
|
129
|
+
|
|
130
|
+
**It is**: a front end that spreads the agent's *process* out in front of you. Thinking blocks, tool calls, changed files, tokens and cost all live in the conversation stream. You can cut in mid-turn, highlight a passage to file a comment on it, or open a scratch chat that never touches disk just to ask one question.
|
|
131
|
+
|
|
132
|
+
**It is not**: a new agent engine, and it is not a SaaS that moves your sessions into the cloud. It does not rewrite prompts and does not take over tool implementations — what you install is pi / Codex / Claude Code / opencode / DeepSeek Harness, and the workbench just gives them a readable UI, clickable buttons, and a session list that survives restarts.
|
|
133
|
+
|
|
134
|
+
Three hard rules:
|
|
135
|
+
|
|
136
|
+
1. **No database**: a conversation *is* the JSONL / thread the engine wrote. The web UI reads it, renames it, and deletes it when asked.
|
|
137
|
+
2. **No pretending**: anything an engine can't do is hidden in the UI (the capability matrix); a panel that can't get data says so, and no other engine's config is passed off as this one's.
|
|
138
|
+
3. **No overreach**: it listens on `127.0.0.1` only by default; exposing it remotely takes all three of `-H`, `-P` and `--allow-host`.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Conversation
|
|
143
|
+
|
|
144
|
+
**Streaming text + collapsible thinking blocks + tool cards.** A tool card shows arguments, the full command (copyable), output, duration and pass/fail. Thinking and tool calls inside one turn are grouped into "process, N steps" blocks that expand when clicked.
|
|
145
|
+
|
|
146
|
+

|
|
147
|
+
|
|
148
|
+
The footer of every reply is the usage **for that turn**: input (cache miss) / output / cache read / cost, with a "Copy" that takes the whole block. The running total for the session is behind the context ring in the status bar (subagents are separate sessions billed separately and are not counted there).
|
|
149
|
+
|
|
150
|
+
A few things in the conversation are clickable:
|
|
151
|
+
|
|
152
|
+
- **Changed-files chip**: which files this reply touched (the chip at the bottom of the screenshot above shows `store.ts`); one click lands you straight on the diff in the right pane.
|
|
153
|
+
- **Branch icon**: "Branch from here", which starts a new conversation at this message; the original stays byte-for-byte unchanged.
|
|
154
|
+
- **File paths**: a path like `web/src/App.tsx` in the body opens in the preview.
|
|
155
|
+
|
|
156
|
+
### Cutting in, queueing, stopping
|
|
157
|
+
|
|
158
|
+
While a turn is running, the composer does not lock up:
|
|
159
|
+
|
|
160
|
+
| Action | Meaning |
|
|
161
|
+
|---|---|
|
|
162
|
+
| **Steer** | Takes effect immediately, inserted into the current turn as the next instruction |
|
|
163
|
+
| **Queue** | Wait until this turn ends; you can see what's at the head of the queue and retract anything |
|
|
164
|
+
| **Stop** | Interrupt the turn and keep whatever was already produced |
|
|
165
|
+
|
|
166
|
+
Steering is pi-only (its SDK has `streamingBehavior: "steer"`). Other engines have no such notion, so the host **degrades it to queueing** rather than firing a second message that would flush the active turn.
|
|
136
167
|
|
|
137
168
|
---
|
|
138
169
|
|
|
139
|
-
##
|
|
170
|
+
## Notes: highlight a passage and comment on it
|
|
171
|
+
|
|
172
|
+
**Select some text in the conversation** and a small toolbar floats up: `Add to session` / `Annotate` / `Ask in a temp session`.
|
|
173
|
+
|
|
174
|
+
<table><tr>
|
|
175
|
+
<td width="50%"><img src="docs/screenshots/14-selection-toolbar.png" alt="The toolbar that floats up after you select a passage"></td>
|
|
176
|
+
<td width="50%"><img src="docs/screenshots/15-annotations.png" alt="After annotating: a numbered badge stays in the body, and a 1-note pill shows up in the composer"></td>
|
|
177
|
+
</tr></table>
|
|
178
|
+
|
|
179
|
+
"Annotate" attaches a comment to that text. The body keeps a **①②③ numbered badge**, and an "N notes" pill appears in the composer — open it to read, edit or delete each comment, or `Quote it`.
|
|
180
|
+
|
|
181
|
+
On send it is assembled into a block like this (you can also hit `Quote it` yourself, in which case only your own words go out):
|
|
140
182
|
|
|
141
183
|
```
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
│ · sessions │ blocks + tool cards) │ (multi-tab) │
|
|
147
|
-
│ · archived │ · steer / queued messages │ · terminal │
|
|
148
|
-
│ · files │ · subagent run strip │ · status bar │
|
|
149
|
-
│ │ · composer (attachments, /) │ │
|
|
150
|
-
└────────────┴──────────────────────────────┴──────────────────────┘
|
|
184
|
+
Note 1:
|
|
185
|
+
> The panel starts at y=0, but the top bar's z-index is 45
|
|
186
|
+
|
|
187
|
+
This needs to be one sentence shorter
|
|
151
188
|
```
|
|
152
189
|
|
|
153
|
-
|
|
190
|
+
Notes are **local anchors**: they locate themselves by "quoted text + surrounding context", so badges still find their place after the body reflows or a stream appends more text. They live in this browser's `localStorage`, isolated per session — never on the server, never in the cloud, invisible from another device.
|
|
154
191
|
|
|
155
|
-
|
|
192
|
+
**Line references in files** are the other road: select lines in the preview (`Shift+click` for a range, `Ctrl/Cmd+click` to add, right-click for the line menu) and "Add to conversation" writes a **path plus line numbers** such as `@web/src/App.tsx:120-138`, leaving the agent to read it.
|
|
156
193
|
|
|
157
194
|
---
|
|
158
195
|
|
|
159
|
-
##
|
|
196
|
+
## Side chat: ask one question and go
|
|
197
|
+
|
|
198
|
+

|
|
199
|
+
|
|
200
|
+
The `Temp session` button in the top bar (or the first card on the right pane's landing page) opens another conversation **in the right pane**:
|
|
201
|
+
|
|
202
|
+
- **Not persisted**: it lives in memory, dies with the tab, never enters the sidebar and leaves no file;
|
|
203
|
+
- the main conversation keeps running; the two don't interrupt each other;
|
|
204
|
+
- to keep it, hit `Save as a regular chat` — only then is a session file written (history the ephemeral chat never had is preserved too);
|
|
205
|
+
- you can have several open at once, each on its own channel and its own tab.
|
|
206
|
+
|
|
207
|
+
> This depends on the engine having an in-memory session: pi supports it; a Codex thread already lives in Codex's own store, so there is no "save" button. It is not "a new session in a different skin", and it is not a subagent — **an ephemeral chat is a window you opened, a subagent is a subtask the agent dispatched**.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Files, diffs, git, search
|
|
212
|
+
|
|
213
|
+
The files area sits at the bottom of the sidebar and also works as a tab in the right pane. **The web side is read-only**: you can look, compare, reference and search; editing files in place and saving them is not this layer's job — give that to the agent's tools or the terminal, and use the diff here to review it.
|
|
214
|
+
|
|
215
|
+
| Capability | Notes |
|
|
216
|
+
|---|---|
|
|
217
|
+
| Directory tree | Switchable root (follow the session / pick a project), lazy loaded, at most 500 entries per directory, `node_modules` / `.git` / `dist` hidden by default, "show hidden files" reveals `.env` and friends |
|
|
218
|
+
| Search by file name | Matches names only, never reads contents, 250 ms debounce, at most 200 hits |
|
|
219
|
+
| Preview | markdown (tables / code highlighting / mermaid), source with line numbers, images, PDF, audio and video streams; multiple tabs, drag to reorder, right-click to close left / right / all, and it can be spread over the full width |
|
|
220
|
+
| Line references | Select lines → "Add to conversation" writes `@path:line`; a text selection can also be "copy selected text" |
|
|
221
|
+
| Reveal in Finder | macOS `open -R`, Windows `explorer.exe /select,`, Linux opens the parent directory |
|
|
222
|
+
| Uncommitted changes | Status dots in the file tree, plus `M` / `U` / `D` after the filename |
|
|
223
|
+
|
|
224
|
+
### Diff
|
|
160
225
|
|
|
161
|
-
|
|
162
|
-
| --- | --- |
|
|
163
|
-
| **pi** (default) | The full plugin / skill ecosystem, lazy tool loading, approval gate, goal mode and subagents; providers and models are managed by this workbench |
|
|
164
|
-
| **Codex** | The official Codex agent (app-server JSON-RPC) with its own loop and sandbox; sessions are shared with Codex Desktop / CLI; approvals are command/file level |
|
|
165
|
-
| **DeepSeek Harness** | The official DeepSeek agent (ACP); model and thinking level are switchable; permissions confirmed one by one |
|
|
166
|
-
| **opencode** | The official opencode agent (ACP) with its own tools / MCP / plugin ecosystem; sessions are shared with the opencode CLI / TUI. **Approvals follow opencode's own `permission` config** (a global allow means you will never be asked) |
|
|
167
|
-
| **fake** | A scripted, zero-token engine used only to exercise the protocol / tools / approvals (`AGENT_WEB_ENGINE=fake`, not shown in the picker by default) |
|
|
226
|
+

|
|
168
227
|
|
|
169
|
-
|
|
228
|
+
The "diff" toggle at the top of the preview is a comparison against `HEAD`: a `+285 −78` summary, line-level red/green, and a switch between "changes only" and the full file. Coming in from a changed-files chip lands directly on the diff.
|
|
170
229
|
|
|
171
|
-
|
|
172
|
-
| --- | :-: | :-: | :-: | :-: |
|
|
173
|
-
| Approvals | ✅ | ✅ | ✅ | per config |
|
|
174
|
-
| Model / thinking level | ✅ | ✅ | ✅ | ✅ |
|
|
175
|
-
| Resume sessions | ✅ | ✅ | ✅ | ✅ |
|
|
176
|
-
| Steering | ✅ | — | — | — |
|
|
177
|
-
| Subagent panel | ✅ | — | — | — |
|
|
178
|
-
| Workbench-managed providers | ✅ | — | — | — |
|
|
230
|
+
### git
|
|
179
231
|
|
|
180
|
-
|
|
232
|
+
The branch chip at the top of the files area lists local branches and switches them (a dirty working tree asks first). It only shells out to `git` for reads and branch switches — it never commits. Committing stays with the agent, or with you in a terminal.
|
|
181
233
|
|
|
182
|
-
|
|
234
|
+
### Content search
|
|
183
235
|
|
|
184
|
-
|
|
185
|
-
| --- | --- |
|
|
186
|
-
| `AGENT_WEB_OPENCODE_BIN` / `_ARGS` / `_MODEL` | opencode binary, extra args (e.g. `--pure` to skip external plugins), preferred model for new sessions (`provider/model`) |
|
|
187
|
-
| `AGENT_WEB_DSH_BIN` / `_HOME` / `_MODEL` / `_PATCH` | DSH binary, data dir, model, patch toggle |
|
|
188
|
-
| `AGENT_WEB_CODEX_BIN` / `_HOME` | Codex binary and data dir |
|
|
236
|
+
"Search file contents" in the toolbar is a full-text search: add a **path mask** (such as `web/src/**`) to narrow it, results show `file:line` plus a snippet of the source, and clicking one jumps to that line. When there are too many hits it truncates at the cap and says so.
|
|
189
237
|
|
|
190
238
|
---
|
|
191
239
|
|
|
192
|
-
##
|
|
240
|
+
## Terminal
|
|
193
241
|
|
|
194
|
-
|
|
242
|
+

|
|
195
243
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
| Codex sessions | Codex's own thread store (via `thread/list \| resume \| delete`) |
|
|
200
|
-
| opencode / DSH sessions | Their own data dirs (opencode lists by cwd; DSH reads the workspace projection under `~/.dsh`) |
|
|
201
|
-
| Session title | pi takes the first user message (reads only the first 60 lines); renaming appends `session_info.name` to the end of the jsonl |
|
|
202
|
-
| Workbench state | `<dataDir>/settings.json`, `approval-rules.json`, `server.lock`, `logs/`, `uploads/`, `push-subscriptions.json`, `vapid-keys.json` |
|
|
244
|
+
The terminal in the right pane is a **real PTY** (`node-pty` + xterm.js): vim / top / Ctrl-C / colors / line editing all behave, the cwd matches the session's project, and you can pass one initial command (the upgrade flow uses exactly that).
|
|
245
|
+
|
|
246
|
+
Reloading the page does not restore a terminal session (the PTY exits with the page); switching tabs does not break it. On Linux `node-pty` has to be compiled in place, and when the tools are missing the UI says exactly what to install.
|
|
203
247
|
|
|
204
|
-
|
|
248
|
+
### Built-in web page
|
|
249
|
+
|
|
250
|
+
The right pane also opens web pages: type a URL and view it in an iframe, with requests going through **a local proxy** (`/web/p/<url>`) — it fetches the document and strips the `X-Frame-Options` / CSP framing restrictions, so sites like Baidu open too. The proxy has boundaries: HTML/CSS documents only, **no cookies in and none out**, a 12 MB upstream cap, and an iframe sandbox without `allow-same-origin`. For sites that need a login or heavy JS, hit `⧉` to jump to the system browser.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Engines: each runs its own native loop
|
|
255
|
+
|
|
256
|
+
The engines are not "the same prompt in different costumes" — each is that vendor's own agent loop:
|
|
257
|
+
|
|
258
|
+
| Engine | How it's wired | Notes |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| **pi** (default) | Native SDK | The full plugin / skill ecosystem, lazy tool loading, the approval gate, subagents, steering; models and providers are managed by this workbench |
|
|
261
|
+
| **Codex** | app-server (JSON-RPC) | Its own loop and sandbox; sessions are shared with Codex Desktop / CLI; approvals are command- and file-level |
|
|
262
|
+
| **DeepSeek Harness** | ACP | Model and thinking level are switchable; permissions confirmed one by one |
|
|
263
|
+
| **opencode** | ACP | Its own tools / MCP / plugin ecosystem; sessions are shared with the opencode CLI / TUI; approvals follow opencode's own `permission` config |
|
|
264
|
+
| **Claude Code** | ACP (the `claude-code-acp` adapter) | Switchable models, per-call tool confirmation; sessions are shared with the `claude` CLI; this ACP surface exposes neither thinking levels nor subagents |
|
|
265
|
+
| **fake** | Built-in scripted engine | Zero tokens, only for exercising the protocol / tools / approval flow (not in the picker by default) |
|
|
266
|
+
|
|
267
|
+
The differences (the capability matrix in `server/engine/registry.ts`, which the UI uses to hide buttons):
|
|
268
|
+
|
|
269
|
+
| Capability | pi | codex | dsh | opencode | claude |
|
|
270
|
+
|---|:-:|:-:|:-:|:-:|:-:|
|
|
271
|
+
| Approvals | ✅ | ✅ | ✅ | per config | ✅ |
|
|
272
|
+
| Model / thinking level | ✅ | ✅ | ✅ | ✅ | model only / no levels |
|
|
273
|
+
| Resume past sessions | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
274
|
+
| Steering | ✅ | — | — | — | — |
|
|
275
|
+
| Subagent panel | ✅ | — | — | — | — |
|
|
276
|
+
| Workbench-managed providers | ✅ | — | — | — | — |
|
|
277
|
+
| Side chat (in memory) | ✅ | — | — | — | — |
|
|
278
|
+
|
|
279
|
+
**The models / plugins / MCP panels follow the active engine**: switch to Codex and the panels read Codex's own data (`model/list`, `plugin/list`, `config/read`); claude reads `~/.claude.json` and `~/.claude/settings.json`; opencode reads `opencode.json`. A panel that has nothing wired says so instead of borrowing pi's config.
|
|
280
|
+
|
|
281
|
+
Engines are switched in the **bottom status bar** (not the top bar), and every session remembers its own engine, model and thinking level.
|
|
205
282
|
|
|
206
283
|
---
|
|
207
284
|
|
|
208
285
|
## Models and providers
|
|
209
286
|
|
|
210
|
-
The models panel
|
|
287
|
+

|
|
288
|
+
|
|
289
|
+
- **Subscriptions**: OAuth login (9 providers), usable right after signing in — no key to copy by hand.
|
|
290
|
+
- **Official built-ins**: the ones pi's catalog carries models for — **paste one key and it works**; endpoints and model tables come from the catalog.
|
|
291
|
+
- **Bring your own**: change the API shape (openai-completions / responses / anthropic-messages / codex / typesafe), the base URL and custom headers, and add models one by one.
|
|
292
|
+
- Tick models individually (only ticked ones are saved), batch-test connectivity, pull the list from `/models`, and save the ticked set as the allowlist.
|
|
211
293
|
|
|
212
|
-
|
|
213
|
-
- Custom providers let you add models, edit base URLs, **import** from another client (actually `GET {baseUrl}/models` and tick the ones you want) and **test each one**.
|
|
214
|
-
- **Keys never leave the server**: the API returns only `hasKey` and the last four digits; writes are serialized inside the process so concurrent edits can't corrupt files.
|
|
294
|
+
**Keys never leave the server**: the API returns only `hasKey` and the last 4 digits; writes are serialized inside the process so concurrent edits can't corrupt a file.
|
|
215
295
|
|
|
216
|
-
The
|
|
296
|
+
The truth is spread across `~/.pi/agent/models.json` (the provider catalog), `models-store.json` (the legacy location) and `auth.json` (`api_key` or OAuth credentials), with the allowlist in `settings.json.enabledModels`.
|
|
217
297
|
|
|
218
298
|
---
|
|
219
299
|
|
|
220
|
-
##
|
|
300
|
+
## Skills
|
|
221
301
|
|
|
222
|
-
|
|
223
|
-
- Identity: loopback peer **and** loopback Host → allowed. With no password set, remote requests always get 403. With a password, either the cookie (`agent-web-auth`, 7 days, HttpOnly) or HTTP Basic will do; failed logins are throttled at 20 attempts / 10 minutes.
|
|
224
|
-
- Tools and commands go through approvals: **read-only tools** (read / grep / find / ls) and read-only commands pass automatically, everything else is asked per `scopeKey` (tool + executable name or target directory). Picking "always allow" writes the rule into `approval-rules.json` (atomic write; a corrupt file is treated as empty).
|
|
225
|
-
- When a turn ends, every pending approval for that session is cleared so nothing hangs waiting for a human.
|
|
226
|
-
- Uploaded temp files and session caches live in the data directory, never in your project.
|
|
302
|
+

|
|
227
303
|
|
|
228
|
-
|
|
304
|
+
Reads `~/.agents/skills/<dir>/SKILL.md`; the list parses frontmatter only (no yaml dependency). **Enabling or disabling means renaming `SKILL.md` to `.SKILL.md.disabled`** — there is no second state file, so what you see in the CLI agrees with what you see here.
|
|
305
|
+
|
|
306
|
+
**Skill Hub**: search by category plus one-click install (200k+ index); it can also install a specific `skills/<name>` from a Git repo, or create one by hand.
|
|
229
307
|
|
|
230
308
|
---
|
|
231
309
|
|
|
232
|
-
##
|
|
310
|
+
## MCP
|
|
233
311
|
|
|
234
|
-
The
|
|
312
|
+

|
|
235
313
|
|
|
236
|
-
|
|
237
|
-
- **Where to watch**: run cards appear under the conversation (the strip above the composer) with status, duration, tool count, tokens and cost. Expand one to see the raw result and its session file path, and stop any of them at any time. Switching sessions swaps the strip to that session's runs. A top-bar badge gives the at-a-glance count.
|
|
238
|
-
- **Management**: the panel manages **templates** (built-in explore / general-purpose / plan, each disableable; create / edit / delete your own). Templates live at `~/.pi/agent/agents/*.md` with frontmatter `name / display_name / description / tools / model / thinking / max_turns`; the body is the system prompt — the same format pi uses, so they're readable, editable and git-friendly.
|
|
239
|
-
- **Concurrency**: a cap of 1–12 (default 4) in the panel; extra delegations queue. Turn the master switch off and the model no longer sees the `Agent` tool.
|
|
240
|
-
- **Isolation**: subagents load no skills / plugins / themes / context files by default (fast and predictable). They inherit the parent's model when they don't pin their own. Models registered by extensions fail inside subagents with "specify a model in the template".
|
|
314
|
+
Reads and writes two config files: `~/.pi/agent/mcp.json` (global) and `<workspace>/.pi/mcp.json` (project), where **a project entry with the same name overrides the global one**, and writes preserve indentation and CRLF.
|
|
241
315
|
|
|
242
|
-
|
|
316
|
+
- exposure has four levels: **codemode (default) / deferred / direct / hidden**;
|
|
317
|
+
- **Test connection**: a real handshake plus `tools/list`, then disconnect; it reports the connection state and the tool count;
|
|
318
|
+
- OAuth login, pick a server from a marketplace, paste a command / URL / JSON and let it be parsed;
|
|
319
|
+
- **the config is the truth**: pi connects at session start, so edits apply to **new sessions**.
|
|
243
320
|
|
|
244
321
|
---
|
|
245
322
|
|
|
246
|
-
##
|
|
323
|
+
## Plugins
|
|
247
324
|
|
|
248
|
-
|
|
249
|
-
Exposure has four levels `codemode | deferred | direct | hidden` and tools are namespaced `mcp__<name>`.
|
|
250
|
-
**The config is the truth** — pi connects at session start, so panel changes apply to **new sessions**. Testing a connection does a real handshake with `@earendil-works/pi-mcp` (`tools/list`) and disconnects immediately; OAuth goes through `pi mcp login`. There's also a marketplace (registry / smithery / github) and a "paste a command / URL / JSON and let it parse" flow.
|
|
325
|
+

|
|
251
326
|
|
|
252
|
-
|
|
327
|
+
Plugins are pi packages: the `packages` entry in `settings.json` (npm / git / local directory) plus the loose `~/.pi/agent/extensions/` and `<ws>/.pi/extensions/`.
|
|
253
328
|
|
|
254
|
-
|
|
255
|
-
**Toggling = renaming `SKILL.md` to `.SKILL.md.disabled`** — there is no second state file. Skill Hub supports category search plus zip installs, and git clone can target `skills/<name>`.
|
|
329
|
+
State comes from the pi SDK's `resolve()` (**querying never triggers `npm install`**), with four states `loaded / installed / missing / disabled`; disabling per package writes `autoload:false` and deletes nothing.
|
|
256
330
|
|
|
257
331
|
---
|
|
258
332
|
|
|
259
|
-
##
|
|
333
|
+
## Subagents: run many, manage each
|
|
260
334
|
|
|
261
|
-
|
|
335
|
+

|
|
262
336
|
|
|
263
|
-
|
|
264
|
-
browser ──GET /api/events (SSE)──▶ server snapshot · message_delta · notice
|
|
265
|
-
──POST /api/rpc (JSON)──▶ ClientRequest → { reply } consumed in place
|
|
266
|
-
```
|
|
337
|
+
Once the main agent has the `Agent` tool it can run several subagents in parallel, and each one is **a real session** (its own context, session file and tool allowlist).
|
|
267
338
|
|
|
268
|
-
- **
|
|
269
|
-
- **
|
|
270
|
-
- **
|
|
271
|
-
- **
|
|
339
|
+
- **Watch**: the subagent card strip above the composer — status, duration, tool count, tokens, cost. "View result" expands the raw result and the session file path in place, and any single run can be stopped. The heading gives the at-a-glance count (`2 running` / `8 finished`).
|
|
340
|
+
- **Manage**: the top-bar "subagents" panel manages **templates** (built in: explore / general-purpose / plan, each disableable; you can also create, edit and delete your own): `name / display_name / description / tools / model / thinking / max_turns`. They land in `~/.pi/agent/agents/*.md`, in the same format as pi's agent files — readable, editable, git-friendly.
|
|
341
|
+
- **Concurrency**: 1–12 (default 4); anything beyond that queues. Turn the master switch off and the model no longer sees the `Agent` tool.
|
|
342
|
+
- **Isolation**: subagents load no skills / plugins / themes / context files by default (fast and predictable); a subagent that doesn't pin a model keeps using the parent session's model.
|
|
272
343
|
|
|
273
|
-
|
|
344
|
+
A subagent's session file is archived next to the parent session (`<parent session dir>/<parent name>/subagents/`) and never shows up in the sidebar's project list.
|
|
274
345
|
|
|
275
346
|
---
|
|
276
347
|
|
|
277
|
-
##
|
|
348
|
+
## Push and voice
|
|
278
349
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
350
|
+
<table><tr>
|
|
351
|
+
<td width="50%"><img src="docs/screenshots/11-push.png" alt="Push: local push state, target devices, test push"></td>
|
|
352
|
+
<td width="50%"><img src="docs/screenshots/10-voice.png" alt="Voice: four event sounds plus local TTS"></td>
|
|
353
|
+
</tr></table>
|
|
282
354
|
|
|
283
|
-
|
|
284
|
-
- Frontend HMR via Vite, backend auto-restart via `tsx --watch`.
|
|
285
|
-
- Phone debugging: `npm run dev -- --host 0.0.0.0`.
|
|
355
|
+
**Push**: Web Push (VAPID) subscriptions, one notification per finished turn — title is the project, body is the session, with a ❌ / ⏹ prefix for failures and interrupts. Multiple devices, a test push, and a one-click clear-all. Needs https or localhost.
|
|
286
356
|
|
|
287
|
-
|
|
288
|
-
| --- | --- |
|
|
289
|
-
| `npm test` | `node --test` over `tests/unit/*.test.ts` (22 files, no extra dependencies) |
|
|
290
|
-
| `npm run typecheck` | Two `tsc --noEmit` runs: server + web |
|
|
291
|
-
| `npm run lint` | oxlint over `server` / `web/src` / `scripts` |
|
|
292
|
-
| `npm run format` | Prettier across the repo (`format:check` only checks; `*.md` is deliberately skipped) |
|
|
293
|
-
| `npm run build` | Server `tsc` + frontend `vite build` into `web/dist` |
|
|
294
|
-
| `npm run icons` | Regenerate PWA icons with playwright-core |
|
|
357
|
+
**Voice**: four event sounds (start / finish / error / waiting for approval) with preview and adjustable volume; local TTS reads the final reply using the browser's built-in voices, with adjustable rate and voice, and never touches the network.
|
|
295
358
|
|
|
296
|
-
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Settings
|
|
362
|
+
|
|
363
|
+

|
|
364
|
+
|
|
365
|
+
The top bar is the entry point for every panel, and **each entry can be hidden in Settings → Interface** (settings and the split toggle are exempt — they're the only way back to the others). The sidebar and the right pane both drag wider and collapse, and their widths are remembered locally in `localStorage`.
|
|
366
|
+
|
|
367
|
+
The "settings" button opens five pages:
|
|
368
|
+
|
|
369
|
+
| Page | Contents |
|
|
370
|
+
|---|---|
|
|
371
|
+
| **Interface** | Which top-bar entries show (text and icon ticked separately), which status-bar chunks show (queue / working / context usage), whether cost shows in the conversation, which blocks sit above the composer (templates / thinking / quick commands), and whether thinking blocks and tool cards start expanded |
|
|
372
|
+
| **General** | The text of your quick phrases and the default thinking level — saved server-side, identical on every device |
|
|
373
|
+
| **Appearance** | Three font sizes (chat body / sidebar project names / sidebar session names, slider 2–20px), content width in 4 steps (720 / 900 / 1100 / full), 6 palettes (bright white, warm paper, mist teal, Tokyo night, mocha, nord), and the top-bar name and logo (hideable, or replaced with your own) |
|
|
374
|
+
| **Language** | Chinese / English, applied immediately |
|
|
375
|
+
| **Shortcuts** | 11 actions, rebindable, clearable and restorable to defaults, plus a cheat sheet |
|
|
376
|
+
|
|
377
|
+
Appearance, interface and language preferences stay on the device only (`localStorage`, with the `agent-web.` prefix) — one copy per phone, tablet and desktop. Only the quick phrases in "General" are shared across devices.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Mobile
|
|
382
|
+
|
|
383
|
+
<table><tr>
|
|
384
|
+
<td width="34%"><img src="docs/screenshots/16-mobile.png" alt="Mobile single column: icon-only top-bar entries, 18px composer"></td>
|
|
385
|
+
<td width="34%"><img src="docs/screenshots/17-mobile-drawer.png" alt="On a phone the project sidebar is an overlay drawer"></td>
|
|
386
|
+
</tr></table>
|
|
387
|
+
|
|
388
|
+
On narrow screens (mobile UA or ≤400px) the layout collapses to a single column:
|
|
389
|
+
|
|
390
|
+
- the sidebar becomes an overlay drawer (`clamp(260px, 76vw, 340px)`, tap the scrim to close, closes on its own after you pick a session);
|
|
391
|
+
- the top bar wraps, keeps icons only, and scrolls horizontally;
|
|
392
|
+
- the right-pane workspace becomes a full-screen second page that starts below the top bar using `100dvh` (dodging the iOS toolbars);
|
|
393
|
+
- the composer is 18px so iOS doesn't zoom on focus; the model menu becomes a bottom sheet;
|
|
394
|
+
- the status bar scrolls horizontally, and the context-usage popover becomes a full-width sheet.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Sessions: pin, archive, fork, move project
|
|
399
|
+
|
|
400
|
+
The sidebar groups sessions into "projects" by directory:
|
|
401
|
+
|
|
402
|
+
| Action | Behaviour |
|
|
403
|
+
|---|---|
|
|
404
|
+
| Pin | Lifts a session or a project to the top |
|
|
405
|
+
| Rename | For pi: append `session_info.name` to the end of the jsonl |
|
|
406
|
+
| Archive | Into "archived", undoable |
|
|
407
|
+
| Delete | Renames to `.deleted-<timestamp>` (the engine's native delete is preferred when it has one) — **the file is still on disk** |
|
|
408
|
+
| Fork | Derive a new session from one message (the title becomes `Branch · …`), the original untouched |
|
|
409
|
+
| Move project | Drag a session row onto another project; the id and history stay, only the `cwd` in the file header changes and the directory is moved |
|
|
410
|
+
|
|
411
|
+
Sorting is a deliberate choice: **newest-created first inside a group** — a new session lands on top, and updating an old one doesn't move it (sort by last activity instead and a single message in an old session shoots it to the top, dragging the whole list along).
|
|
412
|
+
|
|
413
|
+
---
|
|
297
414
|
|
|
298
|
-
|
|
415
|
+
## Shortcuts and slash commands
|
|
416
|
+
|
|
417
|
+
**Every shortcut** is rebindable in Settings → Shortcuts (a binding must include `Mod`/`Alt`; bare letters are rejected). On macOS `Mod` is ⌘, elsewhere it's Ctrl.
|
|
418
|
+
|
|
419
|
+
| Action | Default | Action | Default |
|
|
420
|
+
|---|---|---|---|
|
|
421
|
+
| New session | `Mod+K` | Open right panel | `Mod+Alt+O` |
|
|
422
|
+
| New project | `Mod+M` | Close right panel | `Mod+Alt+W` |
|
|
423
|
+
| Temp session | `Mod+Shift+K` | Toggle left sidebar | `Mod+Alt+L` |
|
|
424
|
+
| Settings | `Mod+Alt+S` | Files | `Mod+Alt+F` |
|
|
425
|
+
| New terminal | `Mod+Alt+T` | Search file contents | `Mod+Shift+F` |
|
|
426
|
+
| Shortcut cheat sheet | `Mod+/` | | |
|
|
427
|
+
|
|
428
|
+
**Slash commands** pop up when you type `/` in the composer. There are two kinds — `local` ones the workbench runs itself, and `to the agent` ones handed to the engine verbatim as a message:
|
|
429
|
+
|
|
430
|
+
| Command | Kind | What it does |
|
|
431
|
+
|---|---|---|
|
|
432
|
+
| `/new [first message]` | local | New conversation, optionally with its first message |
|
|
433
|
+
| `/name <name>` | local | Rename the current session |
|
|
434
|
+
| `/model <name>` | local | Switch model (fuzzy match on id or display name) |
|
|
435
|
+
| `/thinking <level>` | local | Set the thinking level (off / low / … / max) |
|
|
436
|
+
| `/copy` | local | Copy the last assistant message |
|
|
437
|
+
| `/session` | local | Message count / tokens / cost for the session |
|
|
438
|
+
| `/resume` | local | Refresh the session list (sessions another terminal just opened) |
|
|
439
|
+
| `/skill <skill name>` | to the agent | Use a skill (the panel lists the installed ones) |
|
|
440
|
+
| `/compact [note]` | to the agent | Compact the context |
|
|
441
|
+
| `/plan [on\|off]` | to the agent | Turn plan mode on or off |
|
|
442
|
+
| `/cwd <path>` | to the agent | Change the working directory |
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Architecture: SSE + RPC, no WebSocket
|
|
299
447
|
|
|
300
448
|
```
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
│ ├─ cli.ts Command entry: start / stop / restart / status / version / upgrade
|
|
304
|
-
│ ├─ index.ts Process assembly: middleware, routes, static assets, graceful exit
|
|
305
|
-
│ ├─ protocol.ts Single source for the protocol (frontend reuses the types)
|
|
306
|
-
│ ├─ engine/ Engine adapters: pi (native SDK) / codex / dsh / opencode (ACP) / fake
|
|
307
|
-
│ │ plus the capability matrix (registry), catalog, wiring, pi-plugins
|
|
308
|
-
│ ├─ session/ Runtime: runtime, turn-*, approval bridge, rename/delete, lock, settings
|
|
309
|
-
│ ├─ sessions/ HTTP routes for deleting sessions (scanning lives in session/pi-sessions.ts)
|
|
310
|
-
│ ├─ snapshot/ Server state snapshots: state, buildSnapshot, fan-out, 60 ms coalescing
|
|
311
|
-
│ ├─ http/ auth, live-routes (SSE + RPC), aux-routes, compression, file headers
|
|
312
|
-
│ ├─ files/ File tree, preview, search, media streaming, git branches
|
|
313
|
-
│ ├─ terminal/ PTY sessions and their SSE stream
|
|
314
|
-
│ ├─ approval/ Approval scopes and rules
|
|
315
|
-
│ ├─ providers/ Providers / model catalogs / probes / imports / subscription OAuth
|
|
316
|
-
│ ├─ mcp/ mcp.json read-write, connectivity probe, OAuth, marketplace
|
|
317
|
-
│ ├─ skills/ Skill discovery, toggling, Hub installs
|
|
318
|
-
│ ├─ subagents/ Subagent template storage (`~/.pi/agent/agents/*.md`)
|
|
319
|
-
│ ├─ plugins/ HTTP routes for plugin packages
|
|
320
|
-
│ ├─ push/ Web Push (VAPID)
|
|
321
|
-
│ ├─ markers/ Parsing and stream-filtering `[[action:suggest:…]]` markers
|
|
322
|
-
│ └─ util/ env, paths, spawn-cli (cross-platform), origin, etc.
|
|
323
|
-
├─ web/ Frontend (React 19 + Vite + TypeScript)
|
|
324
|
-
│ ├─ src/components/ ~70 components: sidebar, message stream, composer, file tree, terminal, panels
|
|
325
|
-
│ ├─ src/styles/ ~45 sectioned CSS files + six theme palettes (no CSS framework)
|
|
326
|
-
│ ├─ src/ws.ts SSE + RPC client (the name is historical)
|
|
327
|
-
│ └─ src/store.ts Snapshot store (useSyncExternalStore)
|
|
328
|
-
├─ scripts/ Dev dual-process, installers, prebuild pruning, icon generation
|
|
329
|
-
├─ tests/unit/ node:test unit tests
|
|
330
|
-
├─ docs/adr/README.md ADR index
|
|
331
|
-
└─ docs/screenshots/ Real screenshots used by the READMEs (PNG 256 colors, ~1.4 MB)
|
|
449
|
+
browser ──GET /api/events (SSE)──▶ server one snapshot first, deltas afterwards
|
|
450
|
+
──POST /api/rpc (JSON)──▶ ClientRequest → { reply } consumed in place
|
|
332
451
|
```
|
|
333
452
|
|
|
334
|
-
|
|
453
|
+
- **Downstream**: one complete snapshot first, then deltas only. Text arrives as `message_delta` chunks appended block by block; structural changes (tool cards, errors, state) push a fresh snapshot, coalesced in a 60 ms window — snapshots are droppable, events are not. SSE heartbeats every 25 s.
|
|
454
|
+
- **Upstream**: `send_message`, `interrupt`, `approve`, `new_chat` (optionally with `ephemeral`), `switch_conversation`, `set_engine` / `set_model` / `set_thinking_level` / `set_approval_mode`, `persist_conversation`, `close_ephemeral`, `fork_session`, `move_session`, `cancel_queued`, `rename_session` and more.
|
|
455
|
+
- **The protocol has a single source** in `server/protocol.ts`; the frontend reuses its types, so one definition serves both ends.
|
|
456
|
+
- **The snapshot is the only source of truth**: `store.ts` uses `useSyncExternalStore` and replaces everything when a snapshot arrives. Locally only optimistic state survives (`preview` / `draft` / `pendingActive`).
|
|
457
|
+
- **Each client sees its own session** (ADR-0033): one server, two devices, each parked on a different conversation; bulk data such as the session list is only sent to a client when that client needs it.
|
|
335
458
|
|
|
336
|
-
|
|
337
|
-
- 400 lines per file is a guardrail; exceeding it means splitting (`cli-info.ts` and `snapshot/*` exist for that reason).
|
|
338
|
-
- **ADR prose lives in the file-header comment of the code it constrains**, not in standalone `docs/` files — anyone editing the code will read it. `docs/adr/README.md` is only an index from number to file. Update that table when you change the code.
|
|
459
|
+
Process model: `cli.ts` parses the flags → `session/lock.ts` grabs `<dataDir>/server.lock` (a live pid refuses to start, a dead pid means taking over a stale lock) → `runtime.init()` → `listen`. `SIGINT` / `SIGTERM` / `/api/shutdown` all go through the same graceful exit (flush, disconnect engines, release the lock).
|
|
339
460
|
|
|
340
461
|
---
|
|
341
462
|
|
|
342
|
-
##
|
|
463
|
+
## Where data lives
|
|
343
464
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
465
|
+
| Content | Location |
|
|
466
|
+
|---|---|
|
|
467
|
+
| pi sessions | `~/.pi/agent/sessions/<encoded cwd>/<ISO>_<uuid>.jsonl` (first line `{type:"session",id,timestamp,cwd}`) |
|
|
468
|
+
| Codex sessions | Codex's own thread store (`thread/list \| resume \| delete`) |
|
|
469
|
+
| opencode / DSH / claude sessions | Their own data dirs (opencode lists per cwd with `session/list`; DSH reads `~/.dsh`; claude reads `~/.claude`) |
|
|
470
|
+
| Session titles | For pi, the first user message (reads only the first 60 lines); renaming appends `session_info.name` |
|
|
471
|
+
| Workbench state | `<dataDir>/settings.json`, `approval-rules.json`, `server.lock`, `logs/`, `uploads/`, `push-subscriptions.json`, `vapid-keys.json` |
|
|
472
|
+
| Skills / subagent templates / MCP | `~/.agents/skills/`, `~/.pi/agent/agents/`, `~/.pi/agent/mcp.json` |
|
|
473
|
+
| Local UI preferences | Browser `localStorage` (`agent-web.` prefix: theme, font sizes, widths, shortcuts, notes, tabs) |
|
|
347
474
|
|
|
348
|
-
|
|
349
|
-
|---|---|---|---|
|
|
350
|
-
| Developing / building yourself | `npm ci` | 456 | 547 MB |
|
|
351
|
-
| Already built, just run it | `npm ci --omit=dev` | 192 | **158 MB** (~3 s) |
|
|
352
|
-
| Build then slim down | `npm ci && npm run build && npm prune --omit=dev` | 192 | **158 MB** |
|
|
353
|
-
| Ship to another machine | `npm pack` → `npm i -g ./oh-my-agent-web-*.tgz` | 193 | 223 MB (3.1 MB tarball, README screenshots included) |
|
|
475
|
+
---
|
|
354
476
|
|
|
355
|
-
|
|
477
|
+
## Security model
|
|
356
478
|
|
|
357
|
-
-
|
|
358
|
-
-
|
|
479
|
+
- Binds `127.0.0.1` by default and validates `Origin` / `Host` (including the `AGENT_WEB_ALLOWED_HOSTS` allowlist, the vite port and LAN addresses).
|
|
480
|
+
- Identity: a loopback peer **and** a loopback Host → allowed. With no password set, remote requests always get 403. With a password, either the cookie (`agent-web-auth`, 7 days, HttpOnly) or HTTP Basic will do; failed logins are throttled at 20 attempts / 10 minutes.
|
|
481
|
+
- Tools and commands go through approvals: **read-only tools** (read / grep / find / ls) and read-only commands pass automatically, everything else is asked per `scopeKey` (tool + executable name or target directory). Choosing "always allow" writes the rule into `approval-rules.json` (atomic write; a corrupt file counts as empty).
|
|
482
|
+
- When a turn ends, every pending approval for that session is cleared, so nothing hangs waiting for a human.
|
|
483
|
+
- Uploaded temp files and session caches live in the data directory, never in your project.
|
|
484
|
+
- The built-in web page's proxy carries no cookies, and its iframe sandbox omits `allow-same-origin` (otherwise remote JS could reach `localStorage` and the RPC endpoint).
|
|
359
485
|
|
|
360
|
-
>
|
|
361
|
-
> all hard dependencies of `@earendil-works/pi-ai`, unavoidable without trimming vendors.
|
|
486
|
+
> Exposing it remotely is an explicit act: `-H`, `-P` and `--allow-host` must all be present — miss one and it stays shut.
|
|
362
487
|
|
|
363
488
|
---
|
|
364
489
|
|
|
365
|
-
##
|
|
490
|
+
## Development
|
|
366
491
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
492
|
+
From the repo root, run `npm install` first, then:
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
npm run dev # starts both processes with one command
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
- Externally there is still a single port **25257** (Vite listens and proxies); the backend hides on internal **25258**, so dev and production use the same address.
|
|
499
|
+
- Frontend HMR via Vite; the backend auto-restarts through `tsx --watch`.
|
|
500
|
+
- Phone debugging: `npm run dev -- --host 0.0.0.0`.
|
|
501
|
+
|
|
502
|
+
| Command | Purpose |
|
|
503
|
+
|---|---|
|
|
504
|
+
| `npm run typecheck` | Two `tsc --noEmit` runs: server + web |
|
|
505
|
+
| `npm run lint` | oxlint over `server` / `web/src` / `scripts` |
|
|
506
|
+
| `npm run format` | Prettier across the repo (`format:check` only checks; `*.md` is deliberately skipped) |
|
|
507
|
+
| `npm run build` | Server `tsc` + frontend `vite build` into `web/dist` |
|
|
508
|
+
| `npm run icons` | Regenerate the PWA icons with playwright-core |
|
|
509
|
+
|
|
510
|
+
CI (`.github/workflows/ci.yml`): `npm ci` → typecheck → lint → test → build, on ubuntu + Node 22.
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Troubleshooting
|
|
370
515
|
|
|
371
|
-
|
|
516
|
+
> **Why `npm ci` and not `npm install`**: the direct dependencies are all very new, and `npm install` re-resolves the version ranges against the registry — if your mirror (corporate Nexus, npmmirror, …) hasn't synced those versions you get `npm error notarget`. `npm ci` uses the exact versions from the lockfile.
|
|
372
517
|
|
|
373
|
-
1. `npm error notarget No matching version found` → the mirror is behind. Check `npm config get registry`, then
|
|
374
|
-
2. `EBADENGINE` /
|
|
375
|
-
3. `node-pty` fails to build (mostly on Linux) →
|
|
376
|
-
4.
|
|
377
|
-
5. Port already in use → `
|
|
518
|
+
1. `npm error notarget No matching version found` → the mirror is behind. Check `npm config get registry`, then fall back to the official one: `npm -g install oh-my-agent-web --registry=https://registry.npmjs.org/`.
|
|
519
|
+
2. `EBADENGINE` / a Node version complaint at startup → you need Node ≥ 22.19 (check with `node -v`).
|
|
520
|
+
3. `node-pty` fails to build (mostly on Linux) → install `python3` / `make` / `g++` before `npm -g install`, or let the one-line installer handle it with `--with-build-tools`.
|
|
521
|
+
4. It won't start but `oh-my-agent-web status` mentions a stale lock → a previous process didn't exit cleanly; the next `start` takes over automatically. If it's truly stuck, delete `<dataDir>/server.lock`.
|
|
522
|
+
5. Port already in use → `oh-my-agent-web -p 25258`, or run `oh-my-agent-web stop` first.
|
|
523
|
+
6. The built-in web page is blank → that site needs a login or heavy scripts, and the proxy does not tunnel cookies; hit `⧉` to use the system browser.
|
|
378
524
|
|
|
379
|
-
Windows
|
|
525
|
+
Windows differences in shell resolution, process-tree teardown, path handling, permissions and CRLF are all centralised in three modules: `server/util/spawn-cli.ts` (PATH/PATHEXT, `.cmd` via `cmd.exe`, `killTree`), `server/util/paths.ts` and `web/src/path-utils.ts` (separators and absolute paths), and `server/util/file-mode.ts` (`icacls` on Windows). Read those headers before touching cross-platform code.
|
|
380
526
|
|
|
381
527
|
---
|
|
382
528
|
|