skykoi 2026.3.340 → 2026.3.342
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.md +485 -121
- package/dist/{acp-cli-ouJ50hG-.js → acp-cli-CVYseS7Z.js} +7 -7
- package/dist/{admin-unlock-gj-MQxKm.js → admin-unlock-D9kdgQ8v.js} +2 -2
- package/dist/{archive-eBq7w-zH.js → archive-B9j5NN2P.js} +1 -1
- package/dist/{audit-DUfENGRE.js → audit-CLnOGwlN.js} +10 -10
- package/dist/{auth-C6B1VxVI.js → auth-DqeAy3Cg.js} +1 -1
- package/dist/{auth-health-C2fV9Fd9.js → auth-health-DmoN4lSG.js} +1 -1
- package/dist/{bonjour-discovery-_EttiPSR.js → bonjour-discovery-Ci5LSWeP.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/{call-Cz24IGHi.js → call-C9UVp1hU.js} +1 -1
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{channel-options-yVVJPj4e.js → channel-options-C7JjASQk.js} +3 -3
- package/dist/{channel-selection-OgVBkPDG.js → channel-selection-DTkEBU1F.js} +1 -1
- package/dist/{channel-summary-CiOkD9OF.js → channel-summary-BhjG7k3r.js} +18 -12
- package/dist/{channels-cli-BxDh4GsQ.js → channels-cli-CepGnugL.js} +40 -40
- package/dist/{channels-status-issues-T19-LXup.js → channels-status-issues-RnlrwtQu.js} +1 -1
- package/dist/{chrome-B-IUYNJz.js → chrome-Dw_3cCvP.js} +1 -1
- package/dist/cli/daemon-cli.js +1 -1
- package/dist/{cli-if-Ko0qj.js → cli-CYYhBs_X.js} +28 -28
- package/dist/{cli-auto-update-CqfV4Qg9.js → cli-auto-update-CcDCuLjd.js} +3 -3
- package/dist/{completion-cli-DlUzivk_.js → completion-cli-Cjh9ubPc.js} +1 -1
- package/dist/{config-CPGRZ_aH.js → config-CiBJ5Sw5.js} +2 -2
- package/dist/{config-guard-BUqZzzk4.js → config-guard-CU0vhDta.js} +40 -32
- package/dist/{configure-wTTIDt4c.js → configure-DezWAGQv.js} +12 -12
- package/dist/{control-service-cGhUATjJ.js → control-service-cHrnSFJb.js} +4 -4
- package/dist/{control-ui-assets-ulSPw_yr.js → control-ui-assets-CUfeis07.js} +1 -1
- package/dist/{cron-cli-D3p3bDgW.js → cron-cli-Bb8Wjjx7.js} +7 -7
- package/dist/{daemon-cli-unyrNDAd.js → daemon-cli-CP_7sKo5.js} +11 -11
- package/dist/{daemon-runtime-1yCOQiPN.js → daemon-runtime-jG1eA54U.js} +1 -1
- package/dist/{deliver-B5ZswfDv.js → deliver-Bwg-2xqp.js} +6 -6
- package/dist/{deps-B1uCRuzU.js → deps-B8Evgtv2.js} +2 -2
- package/dist/{devices-cli-DOWnFiLF.js → devices-cli-DuyM7cNa.js} +5 -5
- package/dist/{diagnostics-C-YMJXl4.js → diagnostics-BPo5b-50.js} +1 -1
- package/dist/{directory-cli-BZ84RlbK.js → directory-cli-X1J3xQaI.js} +6 -6
- package/dist/{dispatcher-NZrhMfvo.js → dispatcher-C-LUVlX7.js} +1 -1
- package/dist/{dns-cli-Cmpp6Vvg.js → dns-cli-DQca2NRC.js} +4 -4
- package/dist/{docs-cli-CPoQHqu9.js → docs-cli-B3EGr-2u.js} +1 -1
- package/dist/{doctor-CCImfxGD.js → doctor-CgqYyyXq.js} +26 -26
- package/dist/{doctor-completion-dXSUt_OC.js → doctor-completion-C419330G.js} +2 -2
- package/dist/{ensure-local-gateway-D5bQEnlk.js → ensure-local-gateway-iBqdIUtF.js} +5 -5
- package/dist/entry.js +1 -1
- package/dist/{exec-XH65-wH1.js → exec-DdlIawm8.js} +4 -2
- package/dist/{exec-approvals-cli-C86FOoQ8.js → exec-approvals-cli-DFZSyoP-.js} +10 -10
- package/dist/extension-api.js +28 -28
- package/dist/{gateway-cli-DO1vovtZ.js → gateway-cli-MrrB_fKC.js} +278 -81
- package/dist/{gateway-rpc-oeoShcHu.js → gateway-rpc-CBIir0rS.js} +1 -1
- package/dist/{github-copilot-auth-4_9zPSb_.js → github-copilot-auth-DxfhSFQ_.js} +4 -4
- package/dist/{gmail-setup-utils-aNLlRREc.js → gmail-setup-utils-DB6uypHo.js} +1 -1
- package/dist/{health-format-DwTibEYB.js → health-format-jVkaZtVp.js} +8 -8
- package/dist/{hooks-cli-pszRNmom.js → hooks-cli-BoaojBdA.js} +30 -30
- package/dist/{image-D1F8mGc7.js → image-C4yRDi5t.js} +3 -3
- package/dist/{image-ops-bY5IHCXb.js → image-ops-BL6a_ptF.js} +1 -1
- package/dist/index.js +68 -68
- package/dist/{installs-_Nw5_GV7.js → installs-CQUqC8Z-.js} +2 -2
- package/dist/{koi-BZzxHK5u.js → koi-DQfgxiWT.js} +9 -9
- package/dist/{koi-scope-je0O-Kk9.js → koi-scope-7GA83nWp.js} +1 -1
- package/dist/live-broadcast-CJlPQO-e.js +19 -0
- package/dist/{login-CE8OQXwu.js → login-Bx9HuAKm.js} +3 -3
- package/dist/{login-qr-BDQuOnVJ.js → login-qr-S9XrlXNU.js} +1 -1
- package/dist/{logs-cli-C9Skr-Jt.js → logs-cli-Cj-sYnjj.js} +6 -6
- package/dist/{manager-CheecE6N.js → manager-YridT1O9.js} +2 -2
- package/dist/{model-selection-LWVUzs_N.js → model-selection-DvRURdJc.js} +1 -1
- package/dist/{models-cli-R-qiE0Gs.js → models-cli-CCCu5IgB.js} +30 -30
- package/dist/{node-cli-Ci0YkLY9.js → node-cli-DfisfQlb.js} +16 -16
- package/dist/{node-service-DrS2vIzq.js → node-service-WjDdCaA0.js} +1 -1
- package/dist/{nodes-cli-3WP99fZd.js → nodes-cli-DL7LKJ8a.js} +6 -6
- package/dist/{onboard-channels-Uq6qT-Gu.js → onboard-channels-C3se7IsJ.js} +5 -5
- package/dist/{onboard-helpers-CUeATAB3.js → onboard-helpers-BaUchcq-.js} +4 -4
- package/dist/{onboard-skills-CmC8vaO5.js → onboard-skills-B9wJcaBv.js} +9 -9
- package/dist/{onboarding-DnrWsLch.js → onboarding-C9XpjOmT.js} +28 -28
- package/dist/{pairing-cli-B5uRZQBj.js → pairing-cli-DSsU0b-2.js} +7 -7
- package/dist/{pairing-labels-C-enUdKD.js → pairing-labels-D8IFbrVc.js} +1 -1
- package/dist/{pairing-store-T6gWH6ac.js → pairing-store-Dbohn32C.js} +1 -1
- package/dist/{pi-embedded-helpers-BFUPvX5r.js → pi-embedded-helpers-BZAEqMf-.js} +2 -2
- package/dist/{pi-tool-definition-adapter-B5Zq7e5d.js → pi-tool-definition-adapter-Dwkg58f2.js} +2 -2
- package/dist/{pi-tools.policy-BG0SSlKz.js → pi-tools.policy-DYfYE2sn.js} +2 -2
- package/dist/{plugin-auto-enable-I5V3wp0J.js → plugin-auto-enable-mgOtVka_.js} +1 -1
- package/dist/{plugin-registry-DiLPdufR.js → plugin-registry-KBuh-OQA.js} +3 -3
- package/dist/plugin-sdk/index.js +4 -2
- package/dist/{plugins-Ct7Mnq1x.js → plugins-BXfIVhTg.js} +1 -1
- package/dist/{plugins-cli-Bqo0OANi.js → plugins-cli-eOkD8OvR.js} +32 -32
- package/dist/{ports-BamXUQot.js → ports-aBOzofHh.js} +1 -1
- package/dist/{program-Debrr07Q.js → program-Qzt0jo9-.js} +6 -10
- package/dist/{pw-ai-CthVTO-M.js → pw-ai-CJee2_B3.js} +2 -2
- package/dist/{qmd-manager-C_tc1Xq0.js → qmd-manager-riWCwj7I.js} +2 -2
- package/dist/{register.subclis-hGo_4GqB.js → register.subclis-cYZ1CREN.js} +28 -28
- package/dist/{reply-ChoZCU8C.js → reply-B4yWcAqR.js} +37 -37
- package/dist/{routes-JUT9n8s1.js → routes-CzrvdV1c.js} +4 -4
- package/dist/{rpc-CWVZKlO2.js → rpc-B5uz9rXs.js} +1 -1
- package/dist/{run-code-tool-Dr8reO_d.js → run-code-tool-2drimmAk.js} +1 -1
- package/dist/{run-main-Dz44r7PK.js → run-main-B-W02rRR.js} +73 -73
- package/dist/{runner-BCSvAzGx.js → runner-CTmglsQg.js} +6 -6
- package/dist/{sandbox-KwxQsP2x.js → sandbox-QDi_zGUk.js} +6 -6
- package/dist/{sandbox-cli-gWIPQICB.js → sandbox-cli-BR0YcK8N.js} +11 -11
- package/dist/{security-cli-2ugDu_E3.js → security-cli-CpjTGtzu.js} +17 -17
- package/dist/{server-context-aoJXOi8y.js → server-context-DYbJ3M1S.js} +5 -5
- package/dist/{server-node-events-B5_zmtbC.js → server-node-events-DqwK-QAY.js} +30 -30
- package/dist/{service-CKHP-LSk.js → service-BNfl9qMX.js} +1 -1
- package/dist/{service-audit-HStmtL1x.js → service-audit-C5l53T2M.js} +3 -3
- package/dist/{sessions-Cbom-8vC.js → sessions-BJGLVqv9.js} +2 -2
- package/dist/{shared-Ce8XPMG6.js → shared-DhCLX1Xs.js} +1 -1
- package/dist/{shared-DahLhw06.js → shared-tKwE9ewx.js} +1 -1
- package/dist/{skills-cli-CZJ2wYWK.js → skills-cli-DdUZpkjO.js} +4 -4
- package/dist/{status-Bj3xOBqB.js → status-Cfr442Jt.js} +3 -3
- package/dist/{system-cli-LqXPMhHk.js → system-cli-Qcedodyn.js} +6 -6
- package/dist/{system-prompt-snippet-DVjt3zCc.js → system-prompt-snippet-tk2ZN4CE.js} +1 -1
- package/dist/{systemd-D9YMYUVJ.js → systemd-CRc2L6q9.js} +1 -1
- package/dist/{systemd-linger-Bp3jN74v.js → systemd-linger-Qf-ZNSXE.js} +1 -1
- package/dist/{tailscale-D0cB8Nyf.js → tailscale-CBmv5qCh.js} +1 -1
- package/dist/{tool-images-DOz9yj-z.js → tool-images-f3YACc5J.js} +1 -1
- package/dist/{tui-BI8Lmspl.js → tui-CtblgdWZ.js} +15 -7
- package/dist/{tui-cli-BSmOxOHh.js → tui-cli-3SsKIL5I.js} +22 -22
- package/dist/{update-gn_ePcl0.js → update-O979f8y9.js} +1 -1
- package/dist/{update-cli-r_q7gMLS.js → update-cli-Cyb4m9f7.js} +52 -52
- package/dist/{update-runner-16zZxRyN.js → update-runner--zLQ4p6m.js} +2 -2
- package/dist/{webhooks-cli-Cdw6b1wo.js → webhooks-cli-C-7x9fuA.js} +5 -5
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- /package/dist/{declarations-CjH61_I7.js → declarations-CL-Br5Ll.js} +0 -0
- /package/dist/{koi-event-bridge-Cvm1fCDd.js → koi-event-bridge-D4fNtU2m.js} +0 -0
- /package/dist/{koi-utterance-trigger-D8-wlyEh.js → koi-utterance-trigger-C9FSuJKQ.js} +0 -0
package/README.md
CHANGED
|
@@ -1,175 +1,539 @@
|
|
|
1
1
|
# SkyKoi Runtime
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
> The engine behind a **koi**: a personal AI agent that lives on a device, talks to its
|
|
4
|
+
> owner across every messaging channel, runs real work with tools, and remembers.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
This repository is the npm package **`skykoi`** (CLI binaries `koi` and `skykoi`). One
|
|
13
|
+
install bundles three things into one process: an **agent**, a **gateway**, and a
|
|
14
|
+
**multi-channel front door**.
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
flowchart LR
|
|
18
|
+
A["One npm install: skykoi"] --> B["Agent<br/>reasons, calls tools, remembers"]
|
|
19
|
+
A --> C["Gateway<br/>always-on WS / RPC server"]
|
|
20
|
+
A --> D["Front door<br/>WhatsApp, iMessage, Telegram..."]
|
|
21
|
+
```
|
|
7
22
|
|
|
8
|
-
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Table of contents
|
|
26
|
+
|
|
27
|
+
- [What it is](#what-it-is)
|
|
28
|
+
- [System architecture](#system-architecture)
|
|
29
|
+
- [Core vocabulary](#core-vocabulary)
|
|
30
|
+
- [Quick start](#quick-start)
|
|
31
|
+
- [How the program starts](#how-the-program-starts)
|
|
32
|
+
- [Repository map](#repository-map)
|
|
33
|
+
- [Core subsystems](#core-subsystems)
|
|
34
|
+
- [The koi agent loop](#the-koi-agent-loop)
|
|
35
|
+
- [The gateway](#the-gateway)
|
|
36
|
+
- [Channels, routing and pairing](#channels-routing-and-pairing)
|
|
37
|
+
- [Providers and models](#providers-and-models)
|
|
38
|
+
- [Configuration](#configuration)
|
|
39
|
+
- [Memory](#memory)
|
|
40
|
+
- [Cron, infra and self-update](#cron-infra-and-self-update)
|
|
41
|
+
- [Device and browser](#device-and-browser)
|
|
42
|
+
- [Plugins, extensions and native apps](#plugins-extensions-and-native-apps)
|
|
43
|
+
- [Lifecycle of an inbound message](#lifecycle-of-an-inbound-message)
|
|
44
|
+
- [Where to add things](#where-to-add-things)
|
|
45
|
+
- [Build, test and release](#build-test-and-release)
|
|
46
|
+
- [Contributor conventions](#contributor-conventions)
|
|
47
|
+
- [Security model](#security-model)
|
|
48
|
+
- [Further reading](#further-reading)
|
|
49
|
+
|
|
50
|
+
> **How to read this doc.** It is the onboarding map, not the full manual. It is written
|
|
51
|
+
> to stay correct as the code moves, so it follows three rules. Please keep them when you
|
|
52
|
+
> edit: **point to the source of truth, do not duplicate it** (counts, versions and line
|
|
53
|
+
> numbers are deliberately avoided); **key on directories, not files** (directories are
|
|
54
|
+
> stable, files churn); and **explain the why**. The exhaustive manual is
|
|
55
|
+
> [docs.skykoi.com](https://docs.skykoi.com); contributor rules live in
|
|
56
|
+
> [`AGENTS.md`](./AGENTS.md). This README bridges the two.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## What it is
|
|
61
|
+
|
|
62
|
+
SkyKoi Runtime is the program that *is* a koi. It is published to npm and runs **wherever
|
|
63
|
+
the koi lives**: today that is primarily the **user's own device** (the macOS menubar app,
|
|
64
|
+
or any Mac/Linux/Windows host), reachable from the cloud through a tunnel. It can also run
|
|
65
|
+
on a server or VM. (It is host-agnostic, so do not assume EC2; an earlier managed fleet has
|
|
66
|
+
been retired.)
|
|
67
|
+
|
|
68
|
+
A single koi is an LLM-driven loop with a persistent **workspace** and **memory**. The
|
|
69
|
+
runtime wraps that loop in an always-on **gateway** and connects it to the outside world
|
|
70
|
+
through pluggable **channels**, the **CLI/TUI**, and native **apps**.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## System architecture
|
|
75
|
+
|
|
76
|
+
The whole runtime at a glance: every way a message can arrive, funneled into one agent loop
|
|
77
|
+
that is backed by a handful of subsystems.
|
|
78
|
+
|
|
79
|
+
```mermaid
|
|
80
|
+
flowchart TB
|
|
81
|
+
owner(["Owner"])
|
|
82
|
+
|
|
83
|
+
subgraph ways["Ways in"]
|
|
84
|
+
direction LR
|
|
85
|
+
CH["Channels<br/>WhatsApp - iMessage<br/>Telegram - Discord - Slack..."]
|
|
86
|
+
GWc["Gateway clients<br/>web - mobile / desktop apps<br/>platform connect"]
|
|
87
|
+
CLI["CLI / TUI<br/>local terminal"]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
owner --> CH & GWc & CLI
|
|
91
|
+
|
|
92
|
+
CH & GWc & CLI --> RP["Routing + Pairing<br/>which koi? who is this?"]
|
|
93
|
+
RP --> KOI["The koi agent loop<br/>prompt then tool then result"]
|
|
94
|
+
|
|
95
|
+
KOI --> PROV["LLM providers"]
|
|
96
|
+
KOI --> TOOLS["Tools<br/>exec - browser - files - device"]
|
|
97
|
+
KOI --> MEM["Memory<br/>sqlite + vectors"]
|
|
98
|
+
KOI --> WSP["Workspace<br/>KOI / SOUL / USER / MEMORY.md"]
|
|
99
|
+
KOI --> CRON["Cron<br/>scheduled turns"]
|
|
100
|
+
|
|
101
|
+
classDef hot fill:#0aa,stroke:#066,color:#fff;
|
|
102
|
+
class KOI hot;
|
|
103
|
+
```
|
|
9
104
|
|
|
10
|
-
|
|
105
|
+
Viewed as layers, the same system stacks like this. Surfaces depend on the gateway, which
|
|
106
|
+
hosts the agent, which rests on the foundational services:
|
|
107
|
+
|
|
108
|
+
```mermaid
|
|
109
|
+
flowchart TB
|
|
110
|
+
subgraph L4["Surfaces"]
|
|
111
|
+
direction LR
|
|
112
|
+
s1["CLI / TUI"]
|
|
113
|
+
s2["Native apps"]
|
|
114
|
+
s3["Channels"]
|
|
115
|
+
end
|
|
116
|
+
subgraph L3["Gateway · src/gateway"]
|
|
117
|
+
g1["WebSocket / RPC · sessions · heartbeat · control UI"]
|
|
118
|
+
end
|
|
119
|
+
subgraph L2["Agent · src/koi"]
|
|
120
|
+
k1["agent loop · tools · prompt · sessions"]
|
|
121
|
+
end
|
|
122
|
+
subgraph L1["Foundations"]
|
|
123
|
+
direction LR
|
|
124
|
+
f1["providers"]
|
|
125
|
+
f2["config"]
|
|
126
|
+
f3["memory"]
|
|
127
|
+
f4["infra"]
|
|
128
|
+
end
|
|
129
|
+
L4 --> L3 --> L2 --> L1
|
|
130
|
+
```
|
|
11
131
|
|
|
12
|
-
|
|
13
|
-
- LLM inference through AWS Bedrock (Claude Opus 4.6) or any supported provider
|
|
14
|
-
- Tool execution (bash, browser, file operations, cron, etc.)
|
|
15
|
-
- Channel integrations (Discord, Telegram, WhatsApp, Slack, Signal, iMessage, and more)
|
|
16
|
-
- Koi workspace with persistent memory
|
|
17
|
-
- Self-update capability for fleet-wide rolling updates
|
|
132
|
+
---
|
|
18
133
|
|
|
19
|
-
##
|
|
134
|
+
## Core vocabulary
|
|
20
135
|
|
|
21
|
-
|
|
22
|
-
User (browser/app)
|
|
23
|
-
|
|
|
24
|
-
v WebSocket (wss://<id>.gw.skykoi.com)
|
|
25
|
-
+---------------------------+
|
|
26
|
-
| SkyKoi Gateway |
|
|
27
|
-
| (Node.js process) |
|
|
28
|
-
| |
|
|
29
|
-
| - WebSocket server |
|
|
30
|
-
| - Session management |
|
|
31
|
-
| - Koi runtime (Pi) |
|
|
32
|
-
| - Tool execution |
|
|
33
|
-
| - Channel routing |
|
|
34
|
-
| - Heartbeat system |
|
|
35
|
-
| - Cron scheduler |
|
|
36
|
-
+---------------------------+
|
|
37
|
-
|
|
|
38
|
-
v Bedrock API / Provider APIs
|
|
39
|
-
LLM Inference
|
|
40
|
-
```
|
|
136
|
+
These seven terms unlock the codebase.
|
|
41
137
|
|
|
42
|
-
|
|
138
|
+
| Term | Meaning |
|
|
139
|
+
|---|---|
|
|
140
|
+
| **koi** | One agent identity. Has a workspace, memory, model config, and sessions. A host can run several. |
|
|
141
|
+
| **gateway** | The always-on process. Hosts the WebSocket/RPC server, channels, cron, and the koi runtime. |
|
|
142
|
+
| **session** | One conversation thread with a koi, keyed by `(koi, channel, account, peer)`. Persisted as a transcript. |
|
|
143
|
+
| **channel** | A messaging surface (Telegram, iMessage, web...). A pluggable adapter translating native to internal messages. |
|
|
144
|
+
| **command** vs **tool** | A **command** is owner-typed chat text (`/model`, `/reset`) intercepted *before* the LLM. A **tool** is an action the LLM itself calls (`exec`, `browser`, `email`). |
|
|
145
|
+
| **the "Pi" runtime** | The embedded agent core (`@mariozechner/pi-*`). The koi loop wraps it; see `src/koi/pi-embedded*`. |
|
|
146
|
+
| **workspace** | `~/.skykoi/...`: the koi's editable brain on disk (`KOI.md`, `SOUL.md`, `USER.md`, `MEMORY.md`, sessions). |
|
|
43
147
|
|
|
44
|
-
|
|
45
|
-
src/
|
|
46
|
-
kois/ - Koi runtime, tool definitions (exec, process, browser)
|
|
47
|
-
auto-reply/ - Message handling, Koi turn execution, command registry
|
|
48
|
-
channels/ - Channel plugin system (Discord, Telegram, WhatsApp, etc.)
|
|
49
|
-
config/ - Configuration loading, validation, schema
|
|
50
|
-
cron/ - Scheduled jobs, isolated Koi turns
|
|
51
|
-
gateway/ - WebSocket server, RPC handlers, session management
|
|
52
|
-
infra/ - Retry logic, backoff, error handling, updates
|
|
53
|
-
memory/ - Embedding-based memory with SQLite + vector search
|
|
54
|
-
node-host/ - Node device management (camera, screen, location)
|
|
55
|
-
providers/ - LLM provider adapters (Bedrock, Anthropic, OpenAI, Google, etc.)
|
|
56
|
-
browser/ - Chrome/Chromium automation via CDP
|
|
57
|
-
tui/ - Terminal UI for local development
|
|
58
|
-
```
|
|
148
|
+
---
|
|
59
149
|
|
|
60
|
-
##
|
|
150
|
+
## Quick start
|
|
61
151
|
|
|
62
|
-
|
|
152
|
+
> **Requirements:** Node `>= 22`, and **pnpm** (the version is pinned in `package.json`).
|
|
63
153
|
|
|
64
154
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## Running
|
|
155
|
+
pnpm install
|
|
156
|
+
pnpm build # compile src/ to dist/ (tsdown). The CLI always runs dist/.
|
|
69
157
|
|
|
70
|
-
|
|
158
|
+
# Run the CLI from source during development:
|
|
159
|
+
pnpm dev <command> # node scripts/run-node.mjs (rebuilds stale dist, then runs)
|
|
160
|
+
pnpm skykoi --help # list every command
|
|
71
161
|
|
|
72
|
-
|
|
73
|
-
|
|
162
|
+
# Common loops:
|
|
163
|
+
pnpm gateway:dev # run the gateway locally (channels skipped, fast)
|
|
164
|
+
pnpm gateway:watch # gateway with auto-reload on change
|
|
165
|
+
pnpm tui:dev # the terminal chat UI against a dev profile
|
|
74
166
|
```
|
|
75
167
|
|
|
76
|
-
|
|
168
|
+
Quality gates, before pushing anything with logic changes:
|
|
77
169
|
|
|
78
170
|
```bash
|
|
79
|
-
|
|
171
|
+
pnpm check # tsgo (typecheck) + lint + format
|
|
172
|
+
pnpm test # vitest suite (colocated *.test.ts)
|
|
80
173
|
```
|
|
81
174
|
|
|
82
|
-
|
|
175
|
+
> [!IMPORTANT]
|
|
176
|
+
> **`dist/` vs `src/`.** The `koi` binary (`skykoi.mjs`) imports `dist/entry.js`, so a code
|
|
177
|
+
> change is not live on the CLI until it is built. `pnpm dev` and `pnpm gateway:watch`
|
|
178
|
+
> rebuild for you; a bare `koi ...` runs whatever is already in `dist/`.
|
|
83
179
|
|
|
84
|
-
|
|
180
|
+
---
|
|
85
181
|
|
|
86
|
-
|
|
87
|
-
{
|
|
88
|
-
"koi": {
|
|
89
|
-
"model": "amazon-bedrock/us.anthropic.claude-opus-4-6-v1"
|
|
90
|
-
},
|
|
91
|
-
"gateway": {
|
|
92
|
-
"port": 18789
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
On cloud instances, configuration is pushed via SSM after the instance is claimed from the warm pool. The runtime reads it on startup and connects to the platform.
|
|
182
|
+
## How the program starts
|
|
98
183
|
|
|
99
|
-
|
|
184
|
+
Follow this chain once and the entire CLI makes sense.
|
|
100
185
|
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
|
|
186
|
+
```mermaid
|
|
187
|
+
flowchart TB
|
|
188
|
+
bin["skykoi.mjs<br/><i>npm bin</i>"] --> entry["src/entry.ts<br/>title, env, re-spawn, profiles"]
|
|
189
|
+
entry --> main["src/cli/run-main.ts<br/>dotenv, first-run, parse argv"]
|
|
190
|
+
main --> reg["src/cli/program/command-registry.ts<br/>catalog of subcommands"]
|
|
191
|
+
reg --> cmd["src/commands/*<br/>the command implementation"]
|
|
192
|
+
cmd --> deps["createDefaultDeps()<br/>injected config + helpers"]
|
|
193
|
+
```
|
|
104
194
|
|
|
105
|
-
|
|
106
|
-
|
|
195
|
+
| Piece | Role |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `src/cli/` | Commander-based CLI: program construction, argv helpers, help/version, and a **fast-path router** (`src/cli/route.ts`) that shortcuts common read-only commands past full parsing. |
|
|
198
|
+
| `src/cli/deps.ts` | `createDefaultDeps()`: the dependency-injection container (config, workspace, koi helpers) passed into commands so they are testable. |
|
|
199
|
+
| `src/runtime.ts` | The injectable `log` / `error` / `exit` surface, so tests can capture output. |
|
|
200
|
+
|
|
201
|
+
> The default action: `koi` with no args checks login, then drops into the **TUI** chat, or
|
|
202
|
+
> shows the first-run welcome on a fresh machine.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Repository map
|
|
207
|
+
|
|
208
|
+
The product is a **pnpm workspace**: the root package (`skykoi`) plus `extensions/*` (plugins)
|
|
209
|
+
and `apps/*` (native apps). Start with `src/`.
|
|
210
|
+
|
|
211
|
+
| Path | What lives here | Start here |
|
|
212
|
+
|---|---|---|
|
|
213
|
+
| `src/entry.ts`, `src/index.ts`, `src/runtime.ts` | Process bootstrap + public library entry | `src/entry.ts` |
|
|
214
|
+
| `src/cli/`, `src/commands/` | The CLI: command registry + every subcommand | `command-registry.ts` |
|
|
215
|
+
| **`src/koi/`** | **The agent.** The Pi-embedded loop, tools, prompt assembly, sessions, models, sandbox | `pi-embedded-runner/run.ts` |
|
|
216
|
+
| `src/auto-reply/` | Inbound message to command-gating to koi turn to streamed reply | `reply.ts` |
|
|
217
|
+
| **`src/gateway/`** | **The server.** WebSocket + RPC, sessions, heartbeat, control UI, OpenAI-compatible HTTP | `server.impl.ts` |
|
|
218
|
+
| `src/gateway-client.ts` | The WS client apps/devices use to connect | `gateway-client.ts` |
|
|
219
|
+
| `src/channels/` | Channel **plugin system**: adapter interfaces, discovery, allowlists, gating | `plugins/types.core.ts` |
|
|
220
|
+
| `src/telegram/ discord/ slack/ signal/ imessage/ web/ whatsapp/ line/` | Per-channel adapters (native API to internal messages) | each dir entry |
|
|
221
|
+
| `src/routing/`, `src/pairing/` | Map `(channel, account, peer)` to `(koi, session)`; DM pairing and allowlists | `routing/resolve-route.ts` |
|
|
222
|
+
| `src/providers/`, `src/koi/models-config*.ts` | LLM provider adapters and model selection | `models-config.providers.ts` |
|
|
223
|
+
| `src/config/` | Config schema, load/validate `~/.skykoi/skykoi.json`, hot-reload, migrations | `zod-schema.ts`, `paths.ts` |
|
|
224
|
+
| `src/memory/` | Long-term memory: SQLite + vectors (`sqlite-vec`) + hybrid search | `manager.ts` |
|
|
225
|
+
| `src/world-model/` | The per-koi context block injected into the system prompt | `renderer.ts` |
|
|
226
|
+
| `src/cron/` | Scheduled, isolated koi turns | `service.ts` |
|
|
227
|
+
| `src/infra/` | Backoff/retry, update/self-update, exec-approval policy, heartbeat | by filename |
|
|
228
|
+
| `src/node-host/`, `src/browser/` | Device capabilities + Chrome automation (the `nodes` and `browser` tools) | `node-host/runner.ts`, `browser/client.ts` |
|
|
229
|
+
| `src/security/`, `src/gateway/device-auth.ts` | Auth tokens, device pairing, exec policy | `device-auth.ts` |
|
|
230
|
+
| `src/plugins/`, `src/plugin-sdk/` | The plugin loader + the public SDK `extensions/*` build against | `plugin-sdk/index.ts` |
|
|
231
|
+
| `src/tui/` | The terminal chat UI | `tui/` |
|
|
232
|
+
| `extensions/*` | Workspace plugins: extra channels and memory backends | each `package.json` |
|
|
233
|
+
| `apps/macos ios android shared` | Native clients (Swift/Kotlin) that speak the gateway protocol | per-app folder |
|
|
234
|
+
| `docs/` | The Mintlify docs site (docs.skykoi.com) | `docs/index.md` |
|
|
235
|
+
| `dist/` | **Build output. Generated, never edit.** | - |
|
|
236
|
+
|
|
237
|
+
> Some directories hold hundreds of files. The "start here" file is the door; the imports
|
|
238
|
+
> take you the rest of the way. A directory's own `README.md` or doc page outranks this table.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Core subsystems
|
|
243
|
+
|
|
244
|
+
### The koi agent loop
|
|
245
|
+
|
|
246
|
+
`src/koi/` is the heart. A koi "turn" builds context, calls the LLM, runs any tools it asks
|
|
247
|
+
for, feeds results back, and repeats until done. It wraps the embedded **Pi** agent core
|
|
248
|
+
(`@mariozechner/pi-*`; local tweaks live in `patches/`).
|
|
249
|
+
|
|
250
|
+
```mermaid
|
|
251
|
+
flowchart LR
|
|
252
|
+
A["Build context<br/>system prompt + world model<br/>+ workspace + tools"] --> B["Call the LLM"]
|
|
253
|
+
B --> C{"Tool calls?"}
|
|
254
|
+
C -->|yes| D["Run tools<br/>exec - browser - files - email..."]
|
|
255
|
+
D --> E["Feed results back"]
|
|
256
|
+
E --> B
|
|
257
|
+
C -->|no| F["Persist session<br/>stream the final reply"]
|
|
258
|
+
classDef done fill:#0a6,stroke:#063,color:#fff;
|
|
259
|
+
class F done;
|
|
260
|
+
```
|
|
107
261
|
|
|
108
|
-
|
|
109
|
-
|
|
262
|
+
| Area | Where | Notes |
|
|
263
|
+
|---|---|---|
|
|
264
|
+
| Orchestration | `pi-embedded-runner/` | `run.ts` drives the loop; `attempt.ts` is one step; `compact.ts` trims history; `model.ts` picks the model and fails over. |
|
|
265
|
+
| System prompt | `system-prompt.ts` + `src/world-model/` | Assembled from runtime metadata, the world model, workspace files, tools, and channel rules. |
|
|
266
|
+
| Tools | `src/koi/tools/` | One file per capability: `exec`, `browser-tool`, file read/write, `email-tool`, `memory-tool`, `nodes-tool`, `cron-tool`, sub-agents, per-channel `*-actions`. |
|
|
267
|
+
| Sessions | `src/koi/` | Persisted per `(koi, sessionKey)`, guarded against concurrent writes and corruption. |
|
|
268
|
+
| Auth and models | `auth-profiles/`, `model-selection.ts`, `models-config*.ts` | Resolve provider/key/model and fail over when one is unavailable. |
|
|
269
|
+
| Sandbox | `src/koi/sandbox/` | Docker isolation for non-main (group/channel) sessions and risky tool runs. |
|
|
270
|
+
|
|
271
|
+
**The koi's brain on disk** is plain Markdown it reads each turn and can edit:
|
|
272
|
+
|
|
273
|
+
```mermaid
|
|
274
|
+
flowchart LR
|
|
275
|
+
subgraph ws["~/.skykoi workspace"]
|
|
276
|
+
direction TB
|
|
277
|
+
SOUL["SOUL.md<br/>behavior + rules"]
|
|
278
|
+
KOIf["KOI.md<br/>config / personality"]
|
|
279
|
+
IDN["IDENTITY.md<br/>name / avatar"]
|
|
280
|
+
USR["USER.md + profile.json<br/>who the owner is"]
|
|
281
|
+
MEMf["MEMORY.md + memory/*<br/>long-term memory"]
|
|
282
|
+
HB["HEARTBEAT.md<br/>live state / tasks"]
|
|
283
|
+
end
|
|
284
|
+
ws --> sp["into every system prompt"]
|
|
110
285
|
```
|
|
111
286
|
|
|
112
|
-
###
|
|
287
|
+
### The gateway
|
|
288
|
+
|
|
289
|
+
`src/gateway/` is the always-on process that exposes the koi to the world. `server.impl.ts`
|
|
290
|
+
boots the WebSocket server, an HTTP surface (control UI plus an OpenAI-compatible
|
|
291
|
+
`/v1/chat/completions`), the channel manager, cron, heartbeat, and **config hot-reload**.
|
|
292
|
+
|
|
293
|
+
```mermaid
|
|
294
|
+
flowchart TB
|
|
295
|
+
subgraph clients["Clients"]
|
|
296
|
+
direction LR
|
|
297
|
+
c1["macOS / iOS / Android apps"]
|
|
298
|
+
c2["skykoi-live web surface"]
|
|
299
|
+
c3["CLI / TUI"]
|
|
300
|
+
c4["platform connect"]
|
|
301
|
+
end
|
|
302
|
+
clients -->|"WebSocket + RPC"| gw
|
|
303
|
+
|
|
304
|
+
subgraph gw["Gateway process - src/gateway"]
|
|
305
|
+
direction TB
|
|
306
|
+
ws["WS server + RPC handlers<br/>server-methods*.ts"]
|
|
307
|
+
chat["event fan-out<br/>server-chat.ts"]
|
|
308
|
+
cm["channel manager"]
|
|
309
|
+
http["HTTP: control UI + OpenAI-compatible API"]
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
gw --> koi["koi runtime - src/koi"]
|
|
313
|
+
cm --> chans["Channels"]
|
|
314
|
+
```
|
|
113
315
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
316
|
+
> [!NOTE]
|
|
317
|
+
> The **wire protocol** schema is defined in TypeScript and generated to
|
|
318
|
+
> `dist/protocol.schema.json` (plus Swift models) via `scripts/protocol-gen*.ts`. Breaking
|
|
319
|
+
> changes require updating all clients together: run `pnpm protocol:check`.
|
|
320
|
+
|
|
321
|
+
### Channels, routing and pairing
|
|
322
|
+
|
|
323
|
+
Every messaging surface implements the **same adapter interfaces**
|
|
324
|
+
(`src/channels/plugins/types.core.ts`: messaging / auth / outbound / group / command /
|
|
325
|
+
setup). Channels are **discovered and lazy-loaded**; a configured channel that is not
|
|
326
|
+
installed is logged, not fatal. Built-ins live in their own top-level dirs; extra channels
|
|
327
|
+
are `extensions/*` packages built on the `plugin-sdk`.
|
|
328
|
+
|
|
329
|
+
```mermaid
|
|
330
|
+
flowchart TB
|
|
331
|
+
M["Inbound native message"] --> ENV["Envelope<br/>normalized"]
|
|
332
|
+
ENV --> RES["resolve-route.ts"]
|
|
333
|
+
RES --> SK["session-key.ts<br/>channel + account + peer + scope"]
|
|
334
|
+
RES --> PAIR{"known sender?"}
|
|
335
|
+
PAIR -->|no| P["pairing + allowlist<br/>src/pairing"]
|
|
336
|
+
PAIR -->|yes| T["target koi + session"]
|
|
337
|
+
P --> T
|
|
338
|
+
T --> KOI["koi loop"]
|
|
117
339
|
```
|
|
118
340
|
|
|
119
|
-
|
|
341
|
+
> [!WARNING]
|
|
342
|
+
> When you change shared **routing / allowlist / pairing / gating** logic, change it for
|
|
343
|
+
> **all** channels at once. That is a recurring source of bugs (see `AGENTS.md`).
|
|
120
344
|
|
|
121
|
-
###
|
|
345
|
+
### Providers and models
|
|
122
346
|
|
|
123
|
-
|
|
124
|
-
|
|
347
|
+
Adapters for Anthropic, OpenAI, AWS Bedrock, Google Gemini, Ollama, and others, plus the
|
|
348
|
+
custom **"skykoi" provider** that proxies through the platform so a shared key never lands
|
|
349
|
+
on the device. The actual LLM calls go through the Pi core.
|
|
350
|
+
|
|
351
|
+
```mermaid
|
|
352
|
+
flowchart LR
|
|
353
|
+
sel["model-selection.ts<br/>capability + cost + availability"] --> p1{"primary<br/>available?"}
|
|
354
|
+
p1 -->|yes| use["use it"]
|
|
355
|
+
p1 -->|no| fb["fallback chain"]
|
|
356
|
+
fb --> use
|
|
357
|
+
use --> pi["Pi core makes the call"]
|
|
358
|
+
cfg["models-config.providers.ts<br/>+ ~/.skykoi/models.json"] -.-> sel
|
|
125
359
|
```
|
|
126
360
|
|
|
127
|
-
|
|
361
|
+
### Configuration
|
|
128
362
|
|
|
129
|
-
|
|
363
|
+
Config is `~/.skykoi/skykoi.json` (JSON5: comments and trailing commas allowed, with
|
|
364
|
+
`${ENV}` substitution). `paths.ts` resolves locations; **`zod-schema.ts` is the runtime
|
|
365
|
+
source of truth** for valid shape; TypeScript types mirror it in `types*.ts`. Old formats
|
|
366
|
+
are upgraded by `legacy-migrate.ts`, and the gateway hot-reloads most changes.
|
|
130
367
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
4. A wildcard TLS cert from S3 enables `wss://<instanceId>.gw.skykoi.com`
|
|
135
|
-
5. The platform's frontend connects and sends/receives messages via WebSocket RPC
|
|
136
|
-
6. The Koi processes messages through the LLM provider and streams responses back
|
|
137
|
-
7. The runtime heartbeats to the platform every 30 seconds to report health
|
|
368
|
+
> [!NOTE]
|
|
369
|
+
> The root `.env.example` is a stale leftover, ignore it. Real configuration is
|
|
370
|
+
> `~/.skykoi/skykoi.json` plus a handful of provider env vars; see the docs config pages.
|
|
138
371
|
|
|
139
|
-
|
|
372
|
+
### Memory
|
|
140
373
|
|
|
141
|
-
|
|
374
|
+
Long-term recall beyond the live context window: messages and notes are embedded and stored
|
|
375
|
+
in SQLite (`sqlite-vec`); retrieval fuses keyword (BM25) and vector similarity.
|
|
142
376
|
|
|
143
|
-
```
|
|
144
|
-
|
|
377
|
+
```mermaid
|
|
378
|
+
flowchart LR
|
|
379
|
+
msg["messages + notes"] --> emb["embeddings"]
|
|
380
|
+
emb --> db[("SQLite + sqlite-vec")]
|
|
381
|
+
q["koi memory search"] --> hyb["hybrid: BM25 + vectors"]
|
|
382
|
+
db --> hyb
|
|
383
|
+
hyb --> ctx["into the prompt"]
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
> Embeddings index asynchronously, so the newest items can lag the index slightly.
|
|
387
|
+
|
|
388
|
+
### Cron, infra and self-update
|
|
389
|
+
|
|
390
|
+
`src/cron/` runs scheduled, **isolated** koi turns (a reminder, a daily digest) with no live
|
|
391
|
+
channel input, delivering the result to a target. `src/infra/` is the cross-cutting glue:
|
|
392
|
+
backoff, the exec-approval policy engine, heartbeat visibility, and the **self-update** path
|
|
393
|
+
that pulls the latest npm version and restarts the gateway in place (how the fleet rolls
|
|
394
|
+
forward).
|
|
395
|
+
|
|
396
|
+
### Device and browser
|
|
397
|
+
|
|
398
|
+
`src/node-host/` exposes the local machine's capabilities (screenshot, screen frames,
|
|
399
|
+
location) that the koi drives via the `nodes` tool. `src/browser/` is full Chrome automation
|
|
400
|
+
over CDP plus Playwright, powering the `browser` tool and web-page capture.
|
|
401
|
+
|
|
402
|
+
### Plugins, extensions and native apps
|
|
403
|
+
|
|
404
|
+
The plugin loader (`src/plugins/`) discovers packages declaring a `skykoi.extensions` entry
|
|
405
|
+
and built against `skykoi/plugin-sdk`. This is how you add a channel or feature **without
|
|
406
|
+
touching core**. `apps/` holds the native clients (`apps/macos` is the menubar app that
|
|
407
|
+
hosts the gateway today); they are clients of the gateway protocol.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Lifecycle of an inbound message
|
|
412
|
+
|
|
413
|
+
End to end, what happens when a message arrives from a channel:
|
|
414
|
+
|
|
415
|
+
```mermaid
|
|
416
|
+
sequenceDiagram
|
|
417
|
+
actor User
|
|
418
|
+
participant Ch as Channel adapter
|
|
419
|
+
participant AR as auto-reply
|
|
420
|
+
participant Rt as routing
|
|
421
|
+
participant Koi as koi loop
|
|
422
|
+
participant LLM as LLM provider
|
|
423
|
+
participant Tool as Tools
|
|
424
|
+
|
|
425
|
+
User->>Ch: native message
|
|
426
|
+
Ch->>AR: normalize to Envelope
|
|
427
|
+
AR->>AR: command? authorized?
|
|
428
|
+
AR->>Rt: resolve koi + session
|
|
429
|
+
Rt->>Koi: run turn
|
|
430
|
+
loop until done
|
|
431
|
+
Koi->>LLM: messages + tools
|
|
432
|
+
LLM-->>Koi: text or tool call
|
|
433
|
+
Koi->>Tool: execute tool
|
|
434
|
+
Tool-->>Koi: result
|
|
435
|
+
end
|
|
436
|
+
Koi-->>AR: streamed events
|
|
437
|
+
AR-->>Ch: final reply
|
|
438
|
+
Ch-->>User: delivered
|
|
145
439
|
```
|
|
146
440
|
|
|
147
|
-
|
|
441
|
+
The gateway/app path is the same picture, except the entry point is a `chat.send` RPC
|
|
442
|
+
instead of a channel adapter.
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Where to add things
|
|
447
|
+
|
|
448
|
+
| You want to... | Go to | Notes |
|
|
449
|
+
|---|---|---|
|
|
450
|
+
| Add a **tool** the koi can call | `src/koi/tools/` | One file per tool; register it in the runner's toolset. Mind the tool-schema guardrails in `AGENTS.md`. |
|
|
451
|
+
| Add a **CLI command** | `src/commands/` + register in `command-registry.ts` | Take `deps` from `createDefaultDeps()`. |
|
|
452
|
+
| Add a **gateway RPC method** | `src/gateway/server-methods*.ts` + protocol schema | Run `pnpm protocol:gen` and update clients. |
|
|
453
|
+
| Add a **channel** | `extensions/<name>/` against `plugin-sdk` (or a `src/<channel>/` adapter) | Implement the `types.core.ts` interfaces; wire routing/allowlist/gating. |
|
|
454
|
+
| Add an **LLM provider/model** | `models-config.providers.ts` | Add the client init + model defs; selection picks it up. |
|
|
455
|
+
| Change the **system prompt / context** | `system-prompt.ts`, `src/world-model/` | Affects every koi; test broadly. |
|
|
456
|
+
| Change **config shape** | `zod-schema.ts` (+ `types*.ts`, add a migration) | Schema is the runtime source of truth. |
|
|
148
457
|
|
|
149
|
-
|
|
458
|
+
---
|
|
150
459
|
|
|
151
|
-
|
|
460
|
+
## Build, test and release
|
|
152
461
|
|
|
153
|
-
|
|
154
|
-
- `SOUL.md` - Personality and tone
|
|
155
|
-
- `USER.md` - User profile (built over time)
|
|
156
|
-
- `MEMORY.md` - Long-term memory
|
|
157
|
-
- `memory/` - Daily logs and state
|
|
158
|
-
- `BACKLOG.md` - Task tracking
|
|
462
|
+
Everything is in `package.json` scripts (`pnpm run` lists them). The ones you will use most:
|
|
159
463
|
|
|
160
|
-
|
|
464
|
+
```bash
|
|
465
|
+
pnpm build # tsdown: src/ to dist/ (config: tsdown.config.ts)
|
|
466
|
+
pnpm check # typecheck + lint + format (oxlint / oxfmt)
|
|
467
|
+
pnpm test # vitest; pnpm test:coverage for V8 coverage
|
|
468
|
+
pnpm test:live # tests that hit real provider keys (SKYKOI_LIVE_TEST=1)
|
|
469
|
+
pnpm test:docker:* # end-to-end onboarding / gateway / install flows in Docker
|
|
470
|
+
pnpm protocol:check # fail if the generated wire protocol is out of date
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
<details>
|
|
474
|
+
<summary><b>Release and native-version details</b></summary>
|
|
475
|
+
|
|
476
|
+
- **Tests** are colocated `*.test.ts` (e2e: `*.e2e.test.ts`); the full kit is documented in
|
|
477
|
+
`docs/help/testing.md`.
|
|
478
|
+
- **Releases** are gated and manual: read `docs/reference/RELEASING.md` and
|
|
479
|
+
`docs/platforms/mac/release.md` first, and never bump versions or `npm publish` without
|
|
480
|
+
explicit owner sign-off (see `AGENTS.md`).
|
|
481
|
+
- **Native version bumps** touch several files at once: see `AGENTS.md` -> "Version
|
|
482
|
+
locations".
|
|
483
|
+
</details>
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Contributor conventions
|
|
488
|
+
|
|
489
|
+
[`AGENTS.md`](./AGENTS.md) is the detailed playbook (commit/PR flow, docs/i18n rules,
|
|
490
|
+
multi-koi git safety, channel-refactor checklists, release guardrails). The essentials:
|
|
491
|
+
|
|
492
|
+
- **TypeScript, ESM, strict.** Avoid `any`. Keep files reasonably small (~500 LOC guideline;
|
|
493
|
+
`pnpm check:loc`). Run `pnpm check` before you commit.
|
|
494
|
+
- **Add brief comments for non-obvious logic.** Match the surrounding style.
|
|
495
|
+
- **Touch one channel, consider them all** when the change is to shared routing / allowlist /
|
|
496
|
+
pairing / gating / onboarding logic.
|
|
497
|
+
- **Never edit `node_modules` or `dist/`.** Both are generated.
|
|
498
|
+
- **Dependency patches/overrides need explicit approval** and must be pinned to an exact version.
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Security model
|
|
503
|
+
|
|
504
|
+
```mermaid
|
|
505
|
+
flowchart TB
|
|
506
|
+
subgraph trusted["Host - full access"]
|
|
507
|
+
main["main session<br/>tools run on the host"]
|
|
508
|
+
end
|
|
509
|
+
subgraph sandboxed["Docker sandbox"]
|
|
510
|
+
grp["group / channel sessions<br/>+ risky tool runs"]
|
|
511
|
+
end
|
|
512
|
+
unknown(["Unknown sender"]) --> pair["DM pairing required"]
|
|
513
|
+
pair --> main
|
|
514
|
+
sensitive["Sensitive command"] --> approve["exec-approval system"]
|
|
515
|
+
approve --> main
|
|
516
|
+
device(["Gateway client"]) --> auth["device auth"] --> main
|
|
517
|
+
creds["provider keys"] --> proxy["platform proxy<br/>keys stay off device"]
|
|
518
|
+
```
|
|
161
519
|
|
|
162
|
-
|
|
520
|
+
In one breath: the **main** session runs tools on the host with full access; **non-main**
|
|
521
|
+
sessions can be **Docker-sandboxed**; unknown senders must pass **DM pairing**; sensitive
|
|
522
|
+
commands go through **exec-approval**; **device auth** guards the gateway; and the shared-key
|
|
523
|
+
**platform proxy** keeps provider credentials off the device. Report vulnerabilities per
|
|
524
|
+
[`docs/SECURITY.md`](./docs/SECURITY.md).
|
|
163
525
|
|
|
164
|
-
|
|
165
|
-
- Non-main sessions (groups/channels) can be sandboxed via Docker
|
|
166
|
-
- DM pairing by default: unknown senders must authenticate
|
|
167
|
-
- Exec approval system for sensitive commands
|
|
526
|
+
---
|
|
168
527
|
|
|
169
|
-
##
|
|
528
|
+
## Further reading
|
|
170
529
|
|
|
171
|
-
|
|
530
|
+
- **Full docs:** [docs.skykoi.com](https://docs.skykoi.com) (sources in `docs/`: channels,
|
|
531
|
+
gateway, tools, providers, platforms, config, releasing).
|
|
532
|
+
- **Contributor playbook:** [`AGENTS.md`](./AGENTS.md).
|
|
533
|
+
- **The web/voice surface that talks to this runtime:** the `skykoi-live` repo (it connects
|
|
534
|
+
to this gateway for deep work).
|
|
172
535
|
|
|
173
536
|
## License
|
|
174
537
|
|
|
175
|
-
|
|
538
|
+
BUSL-1.1: see [`LICENSE`](./LICENSE) and
|
|
539
|
+
[`docs/THIRD_PARTY_LICENSES.txt`](./docs/THIRD_PARTY_LICENSES.txt).
|