Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
215 commits
Select commit Hold shift + click to select a range
4f67145
chore(hub): platform-neutral companion pairing label
tiann Aug 17, 2026
16ebba1
docs(api): add native client contract (auth, rest, errors)
tiann Aug 17, 2026
1b9ca34
docs(api): add native client contract (sse, pagination, messages)
tiann Aug 17, 2026
e0e7be3
feat(ios): scaffold SwiftUI app + HapiKit package + CI (A-M0)
tiann Aug 17, 2026
83bd25a
feat(android): scaffold Compose app + core modules + CI (B-M0)
tiann Aug 17, 2026
9479f66
feat(fixtures): golden chat fixtures generated from web pipeline (K4+K5)
tiann Aug 17, 2026
d87ce42
merge: K3 pairing label
tiann Aug 17, 2026
68f4f92
merge: K1 client contract docs (auth/rest/errors)
tiann Aug 17, 2026
1a40db3
merge: K2 client contract docs (sse/pagination/messages)
tiann Aug 17, 2026
659fe25
merge: K4+K5 golden fixtures
tiann Aug 17, 2026
2ffaf7f
merge: A-M0 iOS scaffold
tiann Aug 17, 2026
3885f65
merge: B-M0 Android scaffold
tiann Aug 17, 2026
81146e6
docs(api): drop temporary dead-link ignores now that all contract pag…
tiann Aug 17, 2026
25129c5
ci: fixtures drift gate + monorepo conventions for native apps (K8)
tiann Aug 17, 2026
c547f65
merge: K8 fixtures drift gate + monorepo conventions
tiann Aug 17, 2026
c1ecb47
feat(fixtures): batch 2 — events, permissions, sidechains, flavors, c…
tiann Aug 17, 2026
b09dd67
feat(android): protocol wire models, catalogs, session patching (B-M1a)
tiann Aug 17, 2026
e1bfdd6
feat(fixtures): SSE patch + pagination scenario fixtures (K7)
tiann Aug 17, 2026
36a190e
merge: K7 SSE patch + pagination scenario fixtures
tiann Aug 17, 2026
f110845
merge: K6 fixtures batch 2 (events, permissions, sidechains, flavors,…
tiann Aug 17, 2026
a3013d5
merge: B-M1a Android protocol wire models + catalogs + patching
tiann Aug 17, 2026
fada270
docs(api): sse.md — activeTurnStartedAt is not patch-applied (matches…
tiann Aug 17, 2026
1e80327
feat(ios): HapiProtocol wire models, catalogs, session patching (A-M1a)
tiann Aug 17, 2026
6f1dc23
feat(android): auth + HapiApi transport (B-M1b)
tiann Aug 17, 2026
8f7468e
merge: B-M1b Android auth + HapiApi transport
tiann Aug 17, 2026
d39197b
feat(android): markdown/code/diff rendering foundation (B-M2d1)
tiann Aug 17, 2026
483155e
feat(android): SSE engine + reconnect state machine (B-M1c)
tiann Aug 17, 2026
3570017
merge: B-M2d1 Android markdown/code/diff rendering foundation
tiann Aug 17, 2026
f275bae
merge: B-M1c Android SSE engine + reconnect state machine
tiann Aug 17, 2026
1f0ec61
feat(ios): HapiClient API transport + auth (A-M1b)
tiann Aug 17, 2026
7d436aa
merge: A-M1b iOS HapiClient API transport + auth
tiann Aug 17, 2026
15f48c9
feat(ios): SSE client + reconnect state machine (A-M1c)
tiann Aug 17, 2026
9d2ef4e
merge: A-M1c iOS SSE client + reconnect state machine
tiann Aug 17, 2026
ddfe659
feat(ios): HapiUI rendering foundation — markdown, code, diff, theme …
tiann Aug 17, 2026
d6571c1
merge: A-M2e iOS HapiUI rendering foundation
tiann Aug 17, 2026
3cf2a66
feat(android): pairing flow, deep link, DI graphs, navigation skeleto…
tiann Aug 17, 2026
e85ad3f
merge: B-M1d Android pairing flow + DI graphs + navigation
tiann Aug 17, 2026
f702cbf
feat(android): session/machine stores + session list (B-M2b)
tiann Aug 17, 2026
96d81a3
merge: B-M2b Android session/machine stores + session list
tiann Aug 17, 2026
99df45e
feat(android): message window store port, pagination fixtures green (…
tiann Aug 17, 2026
dfcf984
merge: B-M2c Android message window store, pagination fixtures green
tiann Aug 17, 2026
3363d1c
feat(ios): pairing flow, deep link, app session wiring (A-M1d)
tiann Aug 17, 2026
d585232
merge: A-M1d iOS pairing flow + app session wiring
tiann Aug 17, 2026
0365198
feat(android): chat pipeline port — 48 chat fixtures green (B-M2a)
tiann Aug 17, 2026
80948e9
merge: B-M2a Android chat pipeline port (48 fixtures green)
tiann Aug 17, 2026
7c34567
feat(ios): chat pipeline port + fixture harness (A-M2bc)
tiann Aug 17, 2026
ef956af
merge: A-M2bc iOS chat pipeline port + fixture harness
tiann Aug 17, 2026
b23afe2
feat(android): read-only chat screen + store wiring (B-M2d2)
tiann Aug 17, 2026
9875eec
merge: B-M2d2 Android read-only chat assembly
tiann Aug 17, 2026
67b7fe7
feat(ios): session list store + UI (A-M2a)
tiann Aug 17, 2026
2e0386e
merge: A-M2a iOS session list store + UI
tiann Aug 17, 2026
7712a92
feat(ios): message window store port + pagination fixture harness (A-…
tiann Aug 17, 2026
3f497d5
merge: A-M2d iOS message window store + pagination fixture harness
tiann Aug 17, 2026
e640aa4
feat(android): new session flow (B-M3d)
tiann Aug 17, 2026
6247ad3
merge: B-M3d Android new session flow
tiann Aug 17, 2026
a4355d1
feat(ios): read-only chat assembly (A-M2f)
tiann Aug 17, 2026
1972952
merge: A-M2f iOS read-only chat assembly
tiann Aug 17, 2026
78a5ff9
feat(android): composer, permission actions, session config (B-M3ab)
tiann Aug 17, 2026
ca138c9
merge: B-M3ab Android composer + permission actions + session config
tiann Aug 17, 2026
3ce8593
fix(android): dedupe CodexModels wire types from parallel B-M3ab/B-M3…
tiann Aug 17, 2026
fa91f06
feat(ios): new session flow (A-M3c)
tiann Aug 18, 2026
1ddfb7e
merge: A-M3c iOS new session flow
tiann Aug 18, 2026
c164af0
feat(android): dictation, slash commands, session ops (B-M3ce)
tiann Aug 18, 2026
0f347de
merge: B-M3ce Android dictation, slash commands, session ops
tiann Aug 18, 2026
eed3ddd
feat(ios): composer, permission actions, session config (A-M3ab)
tiann Aug 18, 2026
ed310fc
merge: A-M3ab iOS composer + permission actions + session config
tiann Aug 18, 2026
210f9b3
feat(android): files/git browser + file viewer (B-M4c)
tiann Aug 18, 2026
895ea61
merge: B-M4c Android files/git browser + file viewer
tiann Aug 18, 2026
769e0ff
feat(android): usage/storage dashboards + settings scaffold (B-M4e)
tiann Aug 18, 2026
75f8300
merge: B-M4e Android usage/storage dashboards + settings
tiann Aug 18, 2026
ac5cebf
feat(android): composer attachments (B-M3f)
tiann Aug 18, 2026
69b0190
fix(android): missing withContext import after B-M4e navigation merge
tiann Aug 18, 2026
33d186f
feat(android): scratchlist (B-M4d)
tiann Aug 18, 2026
8e5ec6a
merge: B-M3f Android composer attachments
tiann Aug 18, 2026
bf63d2a
feat(android): FCM push + notification actions (B-M4a)
tiann Aug 18, 2026
0f3bf5c
merge: B-M4d Android scratchlist
tiann Aug 18, 2026
53e33be
merge: B-M4a Android FCM push + notification actions
tiann Aug 18, 2026
969caf1
fix(android): re-attach window row status after normalize so failed s…
tiann Aug 18, 2026
8795bab
feat(ios): usage/storage dashboards + settings (A-M4de)
tiann Aug 18, 2026
24c6e77
merge: A-M4de iOS usage/storage dashboards + settings
tiann Aug 18, 2026
05d063c
feat(ios): composer attachments + dictation (A-M3f)
tiann Aug 18, 2026
50a42ec
merge: A-M3f iOS composer attachments + dictation
tiann Aug 18, 2026
a520552
feat(ios): files/git browser + file viewer (A-M4a)
tiann Aug 18, 2026
b9c4d09
merge: A-M4a iOS files/git browser + file viewer
tiann Aug 18, 2026
d83c993
docs(ios): drop leftover merge marker in README
tiann Aug 18, 2026
6c7746d
feat(ios): scratchlist (A-M4b)
tiann Aug 18, 2026
5773ca2
merge: A-M4b iOS scratchlist
tiann Aug 18, 2026
4a57cec
docs(ios): drop leftover merge markers in README
tiann Aug 18, 2026
3510a0f
fix(ios): Linux compile + full package test round — fixtures green lo…
tiann Aug 18, 2026
518d726
merge: A-CI-local iOS Linux compile + full package test round
tiann Aug 18, 2026
641ae3b
feat(android): zh-CN localization + language switching (B-M5a)
tiann Aug 18, 2026
6874908
merge: B-M5a Android zh-CN localization + language switching
tiann Aug 18, 2026
6066f20
feat(ios): zh-CN localization + catalog dedupe (A-M5)
tiann Aug 18, 2026
c4832f3
merge: A-M5 iOS zh-CN localization + catalog dedupe
tiann Aug 18, 2026
b9d5f80
fix(android): device-feedback round 1
tiann Aug 18, 2026
8417c8b
fix(ios): decode fractional fs-mtime epoch fields (device-feedback pa…
tiann Aug 18, 2026
c6f1d27
fix(ios): import SwiftUI alongside PhotosUI for the cross-import overlay
tiann Aug 18, 2026
41c0db1
fix(ios): missing argument label in terminalTitle call
tiann Aug 18, 2026
3300be9
fix(ios): hide steady connection chip; drop blank empty-header sectio…
tiann Aug 18, 2026
54d9592
fix(android): composer bottom bar owns nav-bar + IME insets (edge-to-…
tiann Aug 18, 2026
6557dda
feat: native agent brand icons on both platforms
tiann Aug 18, 2026
828c95b
merge: native agent brand icons on both platforms
tiann Aug 18, 2026
1ad78f4
feat(hub): iOS push channel — direct APNs + relay with E2E envelope (P1)
tiann Aug 18, 2026
25f6371
merge: P1 hub iOS push channel (direct APNs + relay, E2E envelope)
tiann Aug 18, 2026
11d43bf
feat(relay): official push relay — ciphertext-only APNs forwarder (P2)
tiann Aug 18, 2026
0c0c0ca
merge: P2 official push relay (ciphertext-only APNs forwarder)
tiann Aug 18, 2026
e289a0a
feat(ios): push — APNs registration, E2E notification service extensi…
tiann Aug 18, 2026
2f8e699
merge: P3 iOS push — APNs registration, E2E notification service exte…
tiann Aug 18, 2026
1b0a8c5
chore(ios): suppress Xcode-generated noise
tiann Aug 18, 2026
19bb4f6
fix(android): stop the AppCompat legacy IME resize doubling the keybo…
tiann Aug 18, 2026
f72fd87
feat(chat): consolidate top-bar actions into an overflow menu (both p…
tiann Aug 18, 2026
c3248d9
fix(ios): hide the stray separator above the first session row
tiann Aug 18, 2026
8ae402d
test(ios): avoid nested require macros
tiann Aug 18, 2026
04eaca0
feat(sessions): drop the per-row presence dot — dim disconnected rows…
tiann Aug 18, 2026
d52a5a0
feat(sessions): one-line row meta — project · worktree · machine, no …
tiann Aug 18, 2026
4f5a7c8
fix(android): restore the row content-to-gap rhythm after the meta merge
tiann Aug 18, 2026
21a5bf2
feat(sessions): row typography — meta as readable body text, summary …
tiann Aug 18, 2026
c76af90
feat(hub): push config joins the settings.json system (env > file > d…
tiann Aug 18, 2026
3a43624
fix(pi): refresh context after compaction (#1634)
swear01 Aug 19, 2026
2fbd98d
fix(pi): offer model-accurate thinking levels in the create-session f…
KorenKrita Aug 19, 2026
f0e5ba9
feat(codex): mid-turn Steer via app-server turn/steer (#888) (#1606)
swear01 Aug 19, 2026
47c0768
feat(brand): refresh HAPI icons across platforms
tiann Aug 19, 2026
b676faf
feat(android): drop the foreground service — expedited work on API 31…
tiann Aug 19, 2026
a7a3079
docs(website): privacy policy page for the app-store listings
tiann Aug 19, 2026
c62cea9
docs: privacy policy as a VitePress page, replacing the static HTML
tiann Aug 19, 2026
1f5602a
Release version 0.29.0
tiann Aug 19, 2026
0f7a3da
feat(cursor): mid-turn Steer via concurrent ACP session/prompt (#888)…
swear01 Aug 20, 2026
9bdccf0
fix(web): unify message action buttons (#1645)
swear01 Aug 20, 2026
0aebf39
fix(opencode): keep one stored message per reasoning stream (#1643)
junmo-kim Aug 20, 2026
338e405
fix(brand): sharpen iOS and PWA icons
tiann Aug 20, 2026
fdf4fda
feat(web,hub): make large conversation export warning-only (#1648)
swear01 Aug 20, 2026
e3f13c4
feat(web): anchor composer settings sheet to the clicked value button…
KorenKrita Aug 20, 2026
3d94e8e
fix(cli): preserve source extensions for generated media (#1650)
techotaku39 Aug 20, 2026
dd2e978
feat(web): add mark unread session action (#1649)
techotaku39 Aug 20, 2026
c9e243a
docs(macOS): raise launchd runner file limit (#1646)
swear01 Aug 20, 2026
4c7653f
feat: session-attached long-running jobs (#1404)
heavygee Aug 7, 2026
dd5b8bd
feat(jobs): agent guidance + wall-clock elapsed on list chrome
heavygee Aug 7, 2026
a9d3d6c
fix(jobs): address Opus cold-review Majors for #1404
heavygee Aug 7, 2026
bdaf165
fix(jobs): honor explicit startedAt on PUT; document late-attach clock
heavygee Aug 8, 2026
a79356a
fix(jobs): keep merge redirect keys in MetadataSchema (#1404)
heavygee Aug 8, 2026
c386852
feat(jobs): MCP session_job tool for catalog-level discoverability
heavygee Aug 8, 2026
eb44551
feat(web): tri-state pin — default long-running jobs with #1404
heavygee Aug 8, 2026
b3505ae
fix(jobs): cold-review pass 3 Blocker + Majors (#1404)
heavygee Aug 8, 2026
17ffa2c
fix(jobs): close pass-3 minors — stable primary, own-client heartbeats
heavygee Aug 8, 2026
d4e8e53
fix(jobs): refresh JWT for long job-run heartbeats (#1404)
heavygee Aug 8, 2026
61b6561
test(jobs): cover proactive JWT refresh; map 401 to auth_failed
heavygee Aug 8, 2026
71d0220
fix(jobs): stamp fresh startedAt on job run; prefer supervisor
heavygee Aug 8, 2026
2df6c0f
fix(jobs): typecheck-safe assertion for run startedAt
heavygee Aug 8, 2026
5357268
fix(jobs): type put mock args so startedAt assertion typechecks
heavygee Aug 8, 2026
0cceeab
fix(jobs): address Codex Majors — redirect ancestry, heartbeat status…
heavygee Aug 8, 2026
6d7caf2
fix(jobs): type from-session metadata when inheriting job redirects
heavygee Aug 8, 2026
6f84569
fix(jobs): version attachedJob SSE; keep live job on merge collision
heavygee Aug 8, 2026
55a950e
fix(jobs): monotonic attachedJob emit watermark (not primary.updatedAt)
heavygee Aug 9, 2026
67b299a
fix(jobs): one attachedJob watermark allocator for REST and SSE
heavygee Aug 9, 2026
155fd71
fix(jobs): stub allocateAttachedJobVersion in sessions route mocks
heavygee Aug 9, 2026
d68370c
fix(jobs): always record merge redirects even with zero jobs transferred
heavygee Aug 9, 2026
2920069
fix(jobs): install source redirect before merge awaits; allow empty u…
heavygee Aug 9, 2026
be5d378
fix(jobs): expect empty MCP update as heartbeat
heavygee Aug 9, 2026
9148179
fix(jobs): treat merge redirect metadata as hub-owned
heavygee Aug 9, 2026
c216692
fix(jobs): reconcile REST list against attachedJob watermark
heavygee Aug 9, 2026
144840e
fix(jobs): retry terminal status write; reject startedAt on update
heavygee Aug 9, 2026
0b3f25e
fix(jobs): keep both live jobs on same-key merge
heavygee Aug 9, 2026
42c2793
fix(jobs): hard-refuse MCP set; louder stale heartbeat chrome
heavygee Aug 9, 2026
4421f4d
fix(jobs): preserve jobKeyRedirects across metadata merge + A→B→C
heavygee Aug 9, 2026
0bb8924
fix(jobs): keep running-job stubs in sidebar; align bar precedence
heavygee Aug 9, 2026
932394f
fix(jobs): block delete while job running; keep jobful dedup losers
heavygee Aug 9, 2026
99c9dd6
fix(jobs): guard store delete for running jobs; transfer on Codex merge
heavygee Aug 9, 2026
38c7912
test(jobs): stub transferAttachedJobs in Codex duplicate-merge mock
heavygee Aug 9, 2026
db1ac8e
fix(jobs): fence supervisor PATCH with expectedStartedAt
heavygee Aug 9, 2026
0d75fa0
fix(jobs): CAS supervisor writes with UUID runId (schema V24)
heavygee Aug 9, 2026
6eff330
fix(jobs): heartbeat PATCH must not re-send launch --detail
heavygee Aug 9, 2026
6814377
fix(jobs): stamp heartbeatAt on the hub only
heavygee Aug 9, 2026
282f155
docs(jobs): note schema tip V25 after A2A V23 collision
heavygee Aug 10, 2026
be82f6d
fix(jobs): clear stale jobsTransferred redirect on reclaim
heavygee Aug 10, 2026
9ab64b1
fix(jobs): transfer attached jobs on OpenCode /clear
heavygee Aug 10, 2026
f5daebb
fix(jobs): follow job redirects with cycle detection
heavygee Aug 10, 2026
4f59f07
fix(jobs): defer no-engine Codex merge; pending outranks Jobs
heavygee Aug 10, 2026
a12e647
fix(jobs): allocate list watermark before reading jobs
heavygee Aug 10, 2026
59c1bff
fix(jobs): stamp supervised startedAt on the hub clock
heavygee Aug 10, 2026
95e37e2
fix(cli): preserve -- for hapi job run under normalizeCliArgs
heavygee Aug 11, 2026
f421db0
fix(cli): run cliArgs tests under Vitest
heavygee Aug 11, 2026
1c6398c
fix(jobs): allow PATCH null clears from CLI and MCP
heavygee Aug 11, 2026
24eef77
fix(jobs): scope -- keep to job run; expose runId fence on CLI
heavygee Aug 11, 2026
f9a13fa
fix(jobs): fence DELETE/clear with expectedRunId
heavygee Aug 11, 2026
d3c6fc3
fix(jobs): include runId on listSessionJobs for fence recovery
heavygee Aug 11, 2026
3e1d1a6
fix(web): stamp attachedJob on new SessionSummary test helpers
heavygee Aug 11, 2026
d4aa5b4
fix(jobs): fail job run when terminal status never persists
heavygee Aug 11, 2026
2357d91
fix(cursor,web): stop attached-job sessions bouncing Running/Jobs (#1…
heavygee Aug 13, 2026
747e24f
fix(web): do not mask foreground thinking when attached job runs (#1553)
heavygee Aug 13, 2026
328dd3b
fix: rebase onto upstream/main — resolve test mock conflicts
heavygee Aug 15, 2026
e9715c3
fix(jobs): preserve child exit 0 when meter cleared during job run
heavygee Aug 15, 2026
1194270
fix(cursor): filter only debounced running chatter while queue-idle (…
heavygee Aug 15, 2026
43f3740
fix(#1424): trust ACP foreground signals; preflight merge job check
heavygee Aug 15, 2026
1fc2db6
fix(cli): steer agents away from sleep-stub jobs and remaining=0 traps
heavygee Aug 15, 2026
ab7d5fd
fix(cli): steer MCP session_job not_found even when instanceof breaks
heavygee Aug 15, 2026
ef2ffc6
fix(cli): idempotent MCP clear-not-found; reject --heartbeat-sec off run
heavygee Aug 15, 2026
8059330
fix(cli): reject mutation flags on job list/clear and status on run
heavygee Aug 15, 2026
0686392
fix(cli): reject stray MCP fields and non-run command suffix
heavygee Aug 15, 2026
1e4dd4a
fix(hub): preserve runId on corrective job PUT without runId
heavygee Aug 15, 2026
c1f7856
fix(hub): preserve runId on corrective job PUT without runId
heavygee Aug 15, 2026
bf1d19c
docs: mark ALL_DONE late-attach example as completed status
heavygee Aug 15, 2026
6d30267
fix(web,cli): finish #1424 rebase onto upstream pin buckets
heavygee Aug 16, 2026
542e63d
fix(web): rename All activity — quiet connected is not in-progress
heavygee Aug 17, 2026
ccb2b00
docs(guide): session-id contract and remaining vs bar fill
heavygee Aug 17, 2026
ce22d4d
fix(web): bind isNewerVersionedPatch after sessionPatch extract
heavygee Aug 18, 2026
4582f4d
fix(hub): commit job-row move and owner redirects together
heavygee Aug 18, 2026
84f061a
fix(web): drop leftover rebase markers in useSSE imports
heavygee Aug 19, 2026
501ea2e
fix(jobs): fail-closed session id for remote Cursor job run
heavygee Aug 19, 2026
827b7e8
fix(hub): refresh job redirects before scratchlist merge await
heavygee Aug 19, 2026
3150fc4
fix(cursor): ignore ambient ACP running without a prompt in flight
heavygee Aug 19, 2026
d8f18d6
fix(cursor): drop leftover rebase conflict markers in ACP launcher
heavygee Aug 20, 2026
688e51e
fix(cli): sanitize job text before terminal stdout
heavygee Aug 20, 2026
4efc50e
fix(cli): sanitize MCP session_job output via shared formatter
heavygee Aug 20, 2026
a62c9cf
fix(cli): scrub C1 controls in shared job-output sanitizer
heavygee Aug 20, 2026
67d3a03
test(cli): fix C1 sanitizer assertion (content may remain)
heavygee Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
42 changes: 42 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: android

on:
push:
branches:
- main
paths:
- 'android/**'
- 'shared/fixtures/**'
- '.github/workflows/android.yml'
pull_request:
paths:
- 'android/**'
- 'shared/fixtures/**'
- '.github/workflows/android.yml'

permissions:
contents: read

concurrency:
group: android-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: android
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
# Android SDK is preinstalled on GitHub ubuntu runners (licenses
# accepted); AGP auto-installs any missing platform/build-tools.
- uses: gradle/actions/setup-gradle@v4
- name: Protocol tests (pure JVM, fixtures-driven)
run: ./gradlew :core:protocol:test
Comment on lines +39 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run the Android app and data unit tests in CI

Across the checked .github/workflows files, this is the only Gradle test invocation, so CI runs :core:protocol:test but never compiles or executes the new android/core/data/src/test/** and android/app/src/test/** suites; :app:assembleDebug only assembles production code. Consequently the transport, authentication, stores, push handling, and ViewModel regressions covered by those tests can all merge while this workflow remains green. Add :core:data:test and :app:testDebugUnitTest (or an aggregate Gradle verification task) to the workflow.

Useful? React with 👍 / 👎.

- name: Assemble debug APK
run: ./gradlew :app:assembleDebug
58 changes: 58 additions & 0 deletions .github/workflows/fixtures.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: fixtures

on:
push:
branches:
- main
paths:
- 'web/src/chat/**'
- 'web/src/lib/message-window-store.ts'
- 'web/src/lib/sessionPatch.ts'
- 'web/src/lib/messages.ts'
- 'shared/src/**'
- 'web/scripts/**'
- 'shared/fixtures/**'
- '.github/workflows/fixtures.yml'
pull_request:
paths:
- 'web/src/chat/**'
- 'web/src/lib/message-window-store.ts'
- 'web/src/lib/sessionPatch.ts'
- 'web/src/lib/messages.ts'
- 'shared/src/**'
- 'web/scripts/**'
- 'shared/fixtures/**'
- '.github/workflows/fixtures.yml'

permissions:
contents: read

concurrency:
group: fixtures-${{ github.ref }}
cancel-in-progress: true

jobs:
drift-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- run: bun install
- name: Regenerate fixtures from the web pipeline
run: bun run gen:fixtures
- name: Fail on fixtures drift
id: drift
# --intent-to-add makes brand-new fixture files (new cases) visible
# to git diff; deletions of stale files are visible either way.
run: |
git add --intent-to-add shared/fixtures
git diff --exit-code -- shared/fixtures
- name: Explain drift
if: failure() && steps.drift.conclusion == 'failure'
run: echo '::error::web pipeline behavior changed — run `bun run gen:fixtures` and commit the updated fixtures so native ports see the diff'
- name: Web self-conformance (fixture-related tests)
# src/lib/sessionPatch matches nothing until K7 lands its tests;
# vitest unions filters, so the extra filter is future-proof, not fatal.
run: cd web && bun run test -- src/chat/fixtures.test.ts src/lib/message-window-store.test.ts src/lib/messages.test.ts src/lib/sessionPatch
40 changes: 40 additions & 0 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: ios

on:
push:
branches:
- main
paths:
- 'ios/**'
- 'shared/fixtures/**'
- '.github/workflows/ios.yml'
pull_request:
paths:
- 'ios/**'
- 'shared/fixtures/**'
- '.github/workflows/ios.yml'

concurrency:
group: ios-${{ github.ref }}
cancel-in-progress: true

jobs:
package-tests:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Show toolchain versions
run: |
xcodebuild -version
swift --version
- name: Run HapiKit package tests
run: swift test --package-path ios/Packages/HapiKit

app-build:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Show toolchain versions
run: xcodebuild -version
- name: Build Hapi app for iOS Simulator
run: xcodebuild build -project ios/Hapi.xcodeproj -scheme Hapi -destination 'generic/platform=iOS Simulator' CODE_SIGNING_ALLOWED=NO
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ coverage/

# Claude local settings
.claude/settings.local.json
.claude/worktrees/
localdocs/
execplan/

Expand All @@ -50,3 +51,26 @@ e2e-output/
.xyz-harness
.agents/
.pi/

# Xcode / iOS build artifacts
ios/**/xcuserdata/
# Standalone projects recreate this workspace wrapper; keep Package.resolved trackable.
ios/**/*.xcodeproj/project.xcworkspace/contents.xcworkspacedata
ios/**/.build/
ios/**/.swiftpm/
**/*.xcresult
**/DerivedData/

# Android (android/)
android/**/build/
android/.gradle/
android/.kotlin/
android/local.properties
android/captures/
*.keystore
*.jks

# Firebase config is per-operator (official builds inject via CI; self-builds
# drop in their own) — never commit a real one. The committed placeholder is
# android/app/google-services.json.example.
android/app/google-services.json
56 changes: 47 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ Local-first platform for running AI coding agents (Claude Code, Codex, Gemini) w
## Repo layout

```
cli/ - CLI binary, agent wrappers, runner daemon
hub/ - HTTP API + Socket.IO + SSE + Telegram bot
web/ - React PWA for remote control
shared/ - Common types, schemas, utilities
docs/ - VitePress documentation site
website/ - Marketing site
cli/ - CLI binary, agent wrappers, runner daemon
hub/ - HTTP API + Socket.IO + SSE + Telegram bot
web/ - React PWA for remote control
ios/ - Native SwiftUI app (in development)
android/ - Native Kotlin Compose app (in development)
shared/ - Common types, schemas, utilities
shared/fixtures/ - Golden chat fixtures, generated from web pipeline (never hand-edit)
docs/ - VitePress documentation site
website/ - Marketing site
```

Bun workspaces; `shared` consumed by cli, hub, web.
Bun workspaces; `shared` consumed by cli, hub, web. `ios`/`android` outside workspaces (Xcode / Gradle toolchains).

## Architecture overview

Expand Down Expand Up @@ -64,11 +67,15 @@ Bun workspaces; `shared` consumed by cli, hub, web.

```bash
bun typecheck # All packages
bun run test # cli + hub tests
bun run test # cli + hub + web + shared tests
bun run dev # hub + web concurrently
bun run build:single-exe # All-in-one binary
bun run gen:fixtures # Regenerate shared/fixtures/ from web pipeline
cd android && ./gradlew :core:protocol:test # Android protocol conformance
```

iOS tests run in CI (`ios.yml`: macOS `swift test`); no local Xcode/Swift toolchain assumed.

## Key source dirs

### CLI (`cli/src/`)
Expand Down Expand Up @@ -109,6 +116,22 @@ bun run build:single-exe # All-in-one binary
- `messages.ts` - Message parsing utilities
- `modes.ts` - Permission/model mode definitions

### iOS (`ios/`)
- `Packages/HapiKit/` - local SPM package: `HapiProtocol` (wire models + chat pipeline, fixtures-verified), `HapiClient` (API/auth/SSE/stores)
- `Hapi/` + `Hapi.xcodeproj` - thin SwiftUI app target

### Android (`android/`)
- `:core:protocol` - pure JVM wire types + chat pipeline (fixtures-verified)
- `:core:data` - transport (OkHttp/SSE), auth, stores
- `:app` - Compose UI, navigation, deep links, FCM

## Protocol conformance (native apps)

- `shared/fixtures/**` machine-generated from the web chat pipeline (source of truth). NEVER hand-edit; edit `web/scripts/fixtures/cases/` + regenerate.
- Changing `web/src/chat/**`, `web/src/lib/message-window-store.ts`, or `web/src/lib/sessionPatch.ts`: run `bun run gen:fixtures`, commit the diff. CI enforces (`.github/workflows/fixtures.yml`); fixture diffs auto-trigger iOS/Android conformance suites (`ios.yml`/`android.yml`).
- Native client contract docs: `docs/api/client-contract/` (auth, rest, sse, pagination, messages, errors).
- Tracks: `ios/` (SwiftUI, iOS 17+) + `android/` (Kotlin Compose, minSdk 26) — independent codebases, share only contract + fixtures. Plan: `~/.claude/plans/web-pwa-abundant-yeti.md`.

## Pre-push self-review (agents)

Before commit/push/PR: use the **`pre-push-review`** skill (`~/.cursor/skills/pre-push-review/`).
Expand All @@ -124,7 +147,7 @@ Before commit/push/PR: use the **`pre-push-review`** skill (`~/.cursor/skills/pr
- Run: `bun run test` (from root) or `bun run test` (from package)
- Hub tests: `hub/src/**/*.test.ts`
- CLI tests: `cli/src/**/*.test.ts`
- No web tests currently
- Web tests: `web/src/**/*.test.{ts,tsx}` (fixtures self-check: `web/src/chat/fixtures.test.ts`)

## Common tasks

Expand All @@ -139,6 +162,7 @@ Before commit/push/PR: use the **`pre-push-review`** skill (`~/.cursor/skills/pr
| Modify message handling | `hub/src/sync/messageService.ts` |
| Add notification type | `hub/src/notifications/` |
| Add shared type | `shared/src/types.ts`, `shared/src/schemas.ts` |
| Attach outliving job | `cli/src/commands/job.ts`, `docs/guide/session-jobs.md` |

## Important patterns

Expand All @@ -148,6 +172,20 @@ Before commit/push/PR: use the **`pre-push-review`** skill (`~/.cursor/skills/pr
- **Permission modes**: `default`, `acceptEdits`, `auto`, `bypassPermissions`, `plan`
- **Namespaces**: Multi-user isolation via `CLI_API_TOKEN:<namespace>` suffix

## Session-attached jobs (outliving work)

When an agent starts process-shaped work that will keep running after the agent goes idle (`nohup`, batch imports, long scripts, external daemons), attach it so the session list stays truthful while `active: false`. This is **not** thinking progress / todos / in-agent background tools. It is also **not** an A2A Layer 1 `work_ad` ([#1332](https://github.com/tiann/hapi/discussions/1332)) — jobs enrich Layer 0 `SessionSummary`; leave collaboration claims / handoffs to the work-graph ledger.

Agent contract (idle agents cannot heartbeat — bare set + nohup freezes the bar):

1. **Required for process-shaped work:** Shell `hapi job run <session-id> <key> --label … -- <cmd>` (auto-heartbeat + exit status). Use `"$HAPI_SESSION_ID"` only when it matches the operator chat row (`/sessions/<id>` in the web URL); for remote Cursor runner, pass that URL UUID explicitly (shell env can point at a worker row — see `docs/guide/session-jobs.md`).
2. MCP `session_job` **refuses `action=set`**. Use it only for `update` / `clear` / `list` on a job the supervisor already created
3. Manual CLI `set` only with a self-heartbeating wrapper (`update` ≥~10m); never MCP set + nohup
4. Prefer honest `--remaining` or `--done`/`--total`; omit counts if unknown — never invent a percent
5. Elapsed wall clock is always shown from `startedAt` (not an ETA); correct late attach with CLI `set --started-at` (or clear+set)

Full guide: `docs/guide/session-jobs.md`. CLI: `hapi job --help`.

## Adding new web features — consider an FUE

When you ship a non-essential feature (the 20% of sessions, not the 80%), consider wrapping its affordance in the generic First-User-Experience primitive so existing users discover it without a giant always-visible UI block.
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ For self-hosted options (Cloudflare Tunnel, Tailscale), see [Installation](docs/
- [Why HAPI](docs/guide/why-hapi.md)
- [FAQ](docs/guide/faq.md)

## Native apps (iOS / Android)

Fully native SwiftUI and Kotlin Compose clients are in development under `ios/` and `android/`. They pair with your hub by scanning the same terminal QR code as the web app, and follow the same protocol — see the [client contract docs](docs/api/client-contract/index.md).

## Build from source

```bash
Expand Down
Loading
Loading