1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# iOS embedded kcp — plan
Status: 2026-10-30. Lead: atirc-ios-client-dev.
Canonical cross-repo plan: socialweb-computer-kcp
`docs/plans/0038-ios-embedded-kcp.yaml` (plan owner linux-kcp). This file is
the app-side milestone plan; 0038 is the system view. Item mapping:
M1/M2 = I1-BOOT + I2-RUNTIME (done), M2 = I3-PERSIST, M5 = I5-OAUTH,
M3 = I4-SOCIALWEB-IOS (linux-kcp) + I6-POLICY-SANDBOX (linux-kcp) + I7-AGENTS,
M4 = I8-ASK-OWNER, device e2e = I9 (linux-kcp).
Goal: run the real kcp control plane and the socialweb requester inside the
AT-IRC iOS app so the app can launch and manage agents through the same market
request flow the web page uses.
## Architecture (locked decisions)
- **One Go runtime per process.** A combined `AtircGo.xcframework` (package
`github.com/kcp-dev/kcp/contrib/wasm/ios/atircgo`, built with gomobile)
contains both the app's IRC helpers and the kcp bridge. Linking a second
gomobile framework (e.g. a separate KCPGo) crashes at launch: duplicate Go
runtimes. Never add another Go framework; extend `atircgo`.
- **No sockets.** `contrib/wasm/real` boots kcp over an in-process `net.Pipe`
listener/dialer with `memory://` storage. The apiserver never binds a port.
- **Storage.** The patched apiserver memory backend (`KCP_PATCH_MODE=native`,
`k8s.io/apiserver` replaced with the patched copy) plus
`contrib/wasm/storage` snapshot/restore. kcp root lives in
`Application Support/kcp`; the service-account key is ECDSA P-256.
- **Memory.** `KCP_MEMORY_STORAGE=main`, `KCP_LOW_MEMORY=1` (watch cache off,
short watch history), `debug.SetGCPercent(25)` after ready, and a
`debug.SetMemoryLimit(1 GiB)` soft limit. iOS jetsam is the limit, not wasm's
tab heap; measure on a device and raise the limit if the requester needs it.
- **Bridge API** (Swift): `AtircgoKCPStart(root, snapshot)`,
`AtircgoKCPRequest(method, path, headersJSON, body)`,
`AtircgoKCPSnapshot()`, `AtircgoKCPReady()`, `AtircgoKCPStatus()`,
`AtircgoKCPStop()`.
- **Build.** Regenerate the native patched modfile, then
`gomobile bind -target=ios,iossimulator -ldflags="-s -w"` into
`GoLib/AtircGo.xcframework`. The app links `AtircGo` and `-lresolv` (Go's
BIND resolver symbols). Build artifacts are large; keep the release dirs
pruned.
## Milestones
1. **M1 — boots (done).** kcp boots in-process on darwin and iOS; `/version`
and `/apis` return 200; combined framework builds; app compiles and shows a
kcp status bar.
2. **M2 — simulator e2e (done).** Launch in simulator, kcp reaches ready,
status bar shows kcp state. Snapshot persistence implemented: save after
ready and on scenePhase background to `Application Support/kcp/snapshot.b64`
(1.3 MB after a cold boot), restore on launch, fail-closed drop of an
unreadable snapshot. Verified across terminate/relaunch; kcp ready again.
3. **M3 — socialweb + agents (I4 integrated).** The Agents tab starts kcp
lazily (8.7 s in the simulator), then the embedded socialweb requester
against the same kcp (ready ~2.7 s later), and shows "socialweb requester
ready". The Agents API creates the session EphemeralInfra and applies
ComputeContract entries with spec.agent; Release/revoke remain for I7.
Launching is still unavailable/denied until (a) linux-kcp's I6 policy
sandbox runs the requester's tangled-vouch, and (b) pkg/embedded exposes
the page's `PutContractSecrets` (the ATIRC_TOKEN bundle written before the
contract). Both requested.
4. **M4 — ask-owner UI (done, runtime pending deploy).** Pending list, answer
sheet, availability toggle, decided/ADR rows, local notification when mode
is available. Uses the account-level minted atirc token per path (a).
Live calls 401 until atirc-dev deploys the server change that adds the five
ask NSIDs to the minted token scope.
5. **M5 — OAuth scopes (done in simulator).** iOS metadata and authorize
request carry 28 scopes = exact requester-scope.txt (27, r131) plus
`rpc:chat.atirc.revoke?aud=did:web:irc.fedfork.com%23atirc`; dedupe when
socialweb rc133 generates revoke itself. Scripted alice sign-in in the
simulator succeeded end to end (OAuth -> loopback -> DPoP -> mint, 28/28
granted). Device signing/TestFlight pending.
## Workstreams and owners
- kcp core, framework build, app integration: atirc-ios-client-dev (lead).
- ask-owner iOS UI + notification: subagent ask-owner (scope now iOS-only;
server/CLI owned by atirc-dev/atirc-ask).
- OAuth full scopes + Agents nav: subagent scopes-agents.
- Server XRPC (ask/answer/decide/questions/owner_mode), token scopes:
atirc-dev / atirc-ask.
- Wasm reference flow (page) and native-overlay guidance: wasm; source tree
`/Users/johnandersen777/src/linux-kcp/kcp-wasm-mac` is read-only.
## Risks / open decisions
- Memory: watch cache off + GOGC 25; measure with a VM lifecycle. Watch jetsam.
- Snapshot size/write cost: write on a debounce (page uses >=15 s gap + 3 s
trailing), never on every mutation.
- Background: iOS suspends the app; kcp and the requester stall. A release
asked before suspension finishes on the next launch from persisted state;
ask iOS for background time to finish it first (0038 agents decision).
- Policy: the requester runs `requester-tangled-vouch`; iOS has no deno, so it
fails closed until linux-kcp's iOS policy sandbox provider (I6) sets
`PolicyEngine spec.sandbox` with a Prober/Fenced condition. No contract is
created while the policy cannot run.
- Credentials: `~/.aliceoa_bsky_social_source` is sourced only inside the
sign-in command; values never printed/logged/copied; sign-in URLs never
posted.
- App repo is not a git checkout; keep edits local and coordinate files
between the lead and subagents.
## Verification
- Host smoke: `go build -modfile=.go.memory.mod ./contrib/wasm/ios/cmd/kcpsmoke`
then run; expect `real: ready`, `/version` 200, `/apis` APIGroupList.
- Framework: `gomobile bind ... atircgo`; headers expose `AtircgoKCP*`.
- App: `xcodebuild -project AT-IRC.xcodeproj -scheme AT-IRC -destination
'generic/platform=iOS Simulator' build`; install/launch in the booted
simulator; screenshot status bar shows `kcp: ready · <gitVersion>`.