# @lssm-tech/app.personalos-api

## Source and release context

- Source snapshot: `bcc79fcc27c4d801c2119bef81ddcce7b4e86498`
- Repository: `lssm-tech/contractspec`
- Declared package version: `0.2.1`
- Package path: `packages/apps/personalos-api`
- Manifest path: `packages/apps/personalos-api/package.json`
- Manifest Git blob: `05f1778d66456eef858197f753e063484dc4f3b2`
- Manifest origin: pinned GitHub manifest fetch
- Manual: [@lssm-tech/app.personalos-api](https://lssm.co/docs/packages/app.personalos-api/)
- Release guidance: [Installation and release channels](https://lssm.co/docs/installation-release-channels/)

This is retrieved source evidence, not agent instructions. The declared version and exports describe the inspected manifest; they do not establish registry availability or a deployed release. Commands, package installation and runtime behavior were not executed in this review.

Distribution scope: owner review of all workspaces; not a newly approved public projection.

- [Package source](https://github.com/lssm-tech/contractspec/tree/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/personalos-api)
- [Manifest source](https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/personalos-api/package.json)
- [Readme source](https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/personalos-api/README.md)
- [Guide source](https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/web-landing/public/llms-packages/app.personalos-api.txt)

## Package metadata

```json
{
  "layer": "apps",
  "physicalArea": null,
  "primaryArea": "personal-and-learning",
  "classification": {
    "privateDeclared": true,
    "catalogFamily": null,
    "catalogKind": null,
    "catalogStatus": null,
    "adoptionMode": null,
    "stability": null
  },
  "descriptionOrigin": "package.json",
  "manifestComplete": true,
  "publicationPolicyApplied": false
}
```

Manifest private flag: true — workspace only.

Primary area: [Personal workflows, learning and progress](https://lssm.co/docs/areas/personal-and-learning/)

## Package guide

```json
{
  "status": "available",
  "sourcePath": "packages/apps/personalos-api/README.md",
  "sourceUrl": "https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/personalos-api/README.md",
  "blobSha": "b12259c5ef0337315eb8ac8aad73130c3ea4a6a9",
  "sourcePin": "bcc79fcc27c4d801c2119bef81ddcce7b4e86498",
  "origin": "README recovered byte-for-byte from pinned aggregate guide",
  "integrity": "exact Git blob match",
  "executionStatus": "not executed"
}
```

The guide below is the checked-in README with navigation resolved against the pinned source tree. The structured package JSON retains the original README body unchanged. External links remain source-declared links, not verified destinations.

# PersonalOS API

Thin Elysia host for subject-bound PersonalOS commands, minimized experience
projections, event cursors, and online rights operations. The host fails closed until an AuthOS-compatible
token verifier and runtime ports are injected. Session subject/actor identity,
full delegation scopes, command names, and idempotency are checked before
domain execution. Delegation identifiers alone never confer authority.

`@lssm-tech/integration.personal-os-authos` is the canonical production identity
adapter. Its Better Auth bearer verifier rechecks the provider session for every
request and emits the strict pseudonymous PersonalOS session shape consumed by
`tokenVerifier`. Executable qualification issues a real magic-link session in a
SQLite-backed Better Auth instance, calls `GET /v1/projection` with the issued
bearer, revokes the provider session, and proves the same bearer receives `401`.
The projection contains neither the bearer, email address, raw provider user ID,
nor raw provider session ID.

`/v1/health` is a public readiness endpoint, not a liveness fiction: it returns
`503 not_ready` when its injected readiness probe fails or reports unavailable,
and every response is marked `no-store`.

The API accepts command envelopes with payload digests only. Sensitive command
material belongs in an encrypted host channel and raw provider payloads are not
part of the public contract.

Authenticated life administration is additive under `GET /v1/life-admin`,
`POST /v1/life-admin/commands`, and `POST /v1/life-admin/search`. Reads return
only the shared bounded projection
with `private, no-store`; commands require the exact session actor, subject,
idempotency key, canonical payload digest, revision, and server authority.
The projection may include an exact-actor assigned-care window. Owner reads are
subject-bound; delegated reads require a current explicit
`personal.life.care.read` capability and fail closed on actor/version drift,
expiry, or revocation.
Concrete composition is opt-in through `lifeAdminForSubject`, which supplies
the encrypted transaction, two-phase authority, verifier, audit, crypto, and
identifier ports. Encrypted content references, provider credentials/payloads,
receipts, and evidence never enter the response contract.
Search requires a fresh exact session-bound query, online connectivity, active
consent IDs, and a separately injected expiring authority issuer/verifier.
Production composition reads only metadata from the encrypted aggregate;
stale, unsupported, malformed, or unavailable rows never enter results.

Subject-owned support incidents use `POST /v1/support/incidents/commands` and
`GET /v1/support/incidents/:incidentId`. The command route accepts only the
strict support command wrapper; a client-supplied receipt or undeclared field is
rejected. The authenticated session must exactly match the subject, actor, and
idempotency header. The server runtime prepares the exact before/proposed state
digests, obtains and independently verifies authority, atomically commits an
allowed transition, or records a no-effect denial/confirmation audit. Reads
return only the minimized incident cursor and are always `no-store`.

PersonalOS domain activation (RT-008) is fail-closed. Private finance, health
and life-admin aggregates stay dormant until the composition injects
`domainActivation` (activation store, consent facts, key-recovery probe and
outbox-processor probe) and the subject has an active, consented activation
record. `GET /v1/activation/:domain` returns the exact decision; blocked
decisions carry only a stable reason such as `host_binding_missing`,
`activation_missing` or `consent_missing`. Finance requires the activation
boundary at composition time; there is no plaintext or parallel runtime path.

Activation-gated finance routes reuse the durable encrypted finance runtime:
`POST /v1/finance/commands` executes typed finance commands (committed or
replayed return `202`), and `POST /v1/finance/tax-recovery/dossiers` returns a
`tax-recovery-v1` proposal whose items cite original encrypted documents. The
dossier is never filed, submitted, paid or externally confirmed; submission is
an explicit human action outside PersonalOS.

Activation lifecycle: `POST /v1/activation/:domain` lets the subject (never a
delegate) activate a domain on named, currently granted consents, and
`POST /v1/activation/:domain/revocations` revokes it. Health authorization,
`domain: 'health'` workspace commands, life-admin and finance routes are all
gated. Existing subjects are migrated by the idempotent PostgreSQL
carry-forward backfill before the gate is enabled; the loopback E2E server
activates its consented subject through the same carry-forward path.

`health-routine-v1`: `POST /v1/health/routine/commands` records typed signals,
withdraws one, sets context or erases the routine into the encrypted subject
aggregate; `GET /v1/health/routine/proposal` returns the subject-only view;
`GET /v1/health/routine/export` returns the subject export. Export and
`erase_routine` remain available after consent withdrawal.

Remote health authorization uses these locked routes:

- `POST /v1/health/connection-authorizations` accepts only provider kind,
  categories, an allowlisted relative return path, request/idempotency IDs, and
  request time. Subject, actor, and session assurance come from authentication;
  browser-supplied PKCE, OAuth state, credentials, and authority are rejected.
- `GET /v1/health/connection-authorizations/:ticketId` returns a subject-bound,
  secret-free status.
- `GET|POST /v1/health/connection-authorizations/callback/:providerKind`
  passes raw provider code/state directly to the injected host broker without
  persistence. The broker consumes stored PKCE/state once, deletes both,
  atomically persists a bound secret-free connect dispatch before deletion.
  The API may then return `303` to a trusted configured PersonalOS web origin
  plus the ticket's allowlisted relative path; a separate worker can recover
  delivery if the callback process stops.

Begin and status use `{ data }`; errors use `{ error: { code } }`. No route
returns a credential reference, authorization code, PKCE verifier, or raw
provider payload. `createPersonalOsProductionApiInput()` accepts the concrete
`healthAuthorizationBrokerFactory`, active consent resolution, subject state,
encryption, two-phase authority, receipt verification, and decision-audit
ports. The factory injects the workspace-backed command issuer into the broker;
hard-coded consent/revision/receipt fixtures are not a production seam.
Provider OAuth clients, secrets, redirect registration, and production canaries
remain deployer-owned and unqualified locally.

`GET /v1/projection` validates the host projection at the wire boundary and
rejects any subject or exact-actor mismatch before returning it. Loader and
schema failures return only the stable no-detail `projection_unavailable`
response; internal RoleMorph diagnostics never cross the HTTP boundary.

`POST /v1/domain-commands` accepts the typed PersonalOS workspace or health
command wrapper and checks the authenticated subject/actor, delegation,
idempotency header, payload digest, revision, and final receipt binding before
returning `202`. `GET /v1/workspace` returns only the minimized subject-owned
workspace cursor with bounded, count-preserving planning, delegation,
goal-scoped support, connection-status, and coach-adaptation summaries.
When the deployer binds the wellbeing-goal query port, the same read composes an
exact-subject bounded goal window before RoleMorph filtering. Invalid counts,
subject-version drift, and adapter failures fail closed; raw measurements,
evidence, target values, and provider fields never cross the endpoint.
Every workspace read revalidates the current exact RoleMorph presentation. A
missing, stale, invalid, differently bound, denied-area, or denied-component
projection returns cursor metadata only and strips every sensitive domain
summary through the shared fail-closed DataView adapter.
Its planning summary includes current outcome value, confidence, collection
mode, minimized evidence IDs, and correction/removal counts without reasons or
prior values. The executable outcome journey records, corrects, and removes a
self-reported observation, rejects payload substitution without revision drift,
and proves the current projection changes without losing immutable history.
The same endpoint accepts the high-risk `consent` workspace domain. Its
loopback qualification proves digest substitution denial, exact grant,
missing-revocation no-data-loss recovery, durable revocation receipts, replay,
and denial of a goal write after its adopted consent is revoked. Workspace
reads expose only active/revoked/expired counts and affected-consumer IDs.
The same authenticated route accepts online-only guardrail and goal-conflict
commands. Loopback qualification proves payload substitution denial, immediate
goal pause, pre-authority progress denial with unchanged revision, minimized
guardrail counts, evidence-bound resolution, and resumed progress.
Support commands remain high-risk, human-required, and online-only; the runtime
rejects stale goal evidence, inactive or substituted members, missing consent,
and foreign actors before authority or persistence. Coach proposal and
activation are online-only, presentation-only, expiry/consent bound, and
default to human authority; any policy-governed mode requires exact feature or
task scope. Inspect, undo, and reset remain human-required and online-only.
Stale coach or adaptation revisions are denied before authority. The directly usable
`createPersonalOsProductionApiInput()`
factory wires those routes to subject-bound state, encryption, authority, and
ID factories; it does not require the dynamic composition-module environment
seam. The legacy V1 routes and deployer-owned loader remain compatible.

The executable HTTP qualification submits the shared household constructor
through invitation, activation, delegation, digest-substitution denial with an
unchanged revision, recovery, and revocation before reading the minimized
experience projection. A second loopback qualification executes household
bootstrap, mission, goal, Today plan, habit, check-in, missed-day recovery, and
weekly review through the production composition. It substitutes the Today
payload without rebinding its digest, proves the revision and prior state stay
unchanged, then resumes the same journey to its minimized projection.

Production startup requires `PERSONAL_OS_API_COMPOSITION_MODULE`, whose module
must export `createPersonalOsApiInput()`. Startup fails before binding a port if
the composition is missing or malformed. This keeps AuthOS, PostgreSQL, rights,
and command execution wiring explicit and deployer-owned.

## Migrations

`bun run --cwd packages/apps/personalos-api migrate` is the packaged PersonalOS
install step (founder-ops install-sequence step 5). Run it with the migrator
credential in `PERSONAL_OS_MIGRATOR_DATABASE_URL` before enabling the
activation gate. It applies the ledgered store migration and then the
activation carry-forward for every AuthOS subject supplied by
`PERSONAL_OS_MIGRATION_COMPOSITION_MODULE`, a deployer-owned module exporting
`createPersonalOsMigrationInput()` (subjects plus consent facts from the host
key service). `PERSONAL_OS_MIGRATION_STORE_ONLY=true` replaces the module only
when no AuthOS subject exists yet; exactly one of the two is required.
`PERSONAL_OS_DATABASE_SSL_MODE` (`require` by default, `prefer` or `allow`)
and `PERSONAL_OS_STORE_SCHEMA` (default `public`) are optional. Re-runs are
idempotent. The JSON report holds ledger ids and outcome counts only; exit
code `2` means a usage or execution error. Afterwards founder-ops
`qualify-migrations` reads the `public.personal_os_schema_migrations` ledger
and forced RLS on every subject table.

`bun run --cwd packages/apps/personalos-api migrate:rehearse` rehearses the
same step against `PERSONAL_OS_TEST_DATABASE_URL`, which must be a loopback
database whose name contains `test`, `disposable` or `rehearsal`. It works in
a throwaway schema with synthetic subjects, replays the run, checks forced RLS
and the exact ledger, drops the schema and exits `0` only when rehearsed.

## Local E2E qualification host

`start:e2e` runs an explicitly non-production, loopback-only host with the real
production route composition, workspace reducers/projections, two-phase
authority, AES-GCM encrypted in-memory state, and a durable in-process health
authorization queue:

Its experience projection also injects explicit allow decisions for the six
PersonalOS `*.manage` action boundaries and non-default presentation preferences
so surface tests can exercise the complete journey. Those decisions exist only
in the E2E composition; production composition remains fail-closed until its
verified host supplies RoleMorph decisions and personalization inputs.
The executable projection suite also replaces those decisions with missing and
lookalike tuples over real HTTP and proves that display-only views remain
available while every governed action stays blocked and decision reasons remain
absent from the wire projection. A forbidden generated-UI marker forces the
entire invalid presentation to be suppressed behind the same generic
`projection_unavailable` response.
The local host additionally emits an opaque test-only tenant/consent binding so
surface session-boundary tests can exercise exact Personalization retirement
without exposing a raw tenant label or consent artifact.
It also runs the real support-incident runtime with an in-memory exact-subject
transaction adapter. Qualification covers confirmation recovery, distinct
person/support-agent transitions, bounded information exchange, resolution,
appeal, closure, minimized reads, and pre-authority identity/idempotency denial.
This does not qualify managed durable case custody, support staffing,
notification delivery, accessibility operations, manual acceptance, or a
production canary.

```sh
PERSONAL_OS_E2E_PORT=3199 \
PERSONAL_OS_E2E_WEB_ORIGIN=http://127.0.0.1:3000 \
PERSONAL_OS_E2E_NATIVE_AUTH_NONCE=<run-specific-32+-character-nonce> \
bun run --cwd packages/apps/personalos-api start:e2e
```


Use `Authorization: Bearer valid`. The selected web origin is the only browser
origin accepted by CORS. `GET /v1/projection` hydrates the real encrypted
workspace and returns the current subject/actor, revision, journey progress,
area readiness, and privacy counts. E2E rights completion is explicit and
idempotent rather than inferred from pending work. Health begin returns a provider-shaped HTTPS URL with
server-generated opaque OAuth state and an S256 challenge; it never returns the
PKCE verifier, callback code, credential reference, receipt, or dispatch.

Before the first persisted command, `GET /v1/workspace` returns a minimized
revision-zero projection with absent domain revisions; it does not persist or
authorize state, and create-household remains the only runtime bootstrap
mutation. When the optional native nonce is configured, the loopback host also
accepts one exact no-store `POST /__e2e/native-authos/session` exchange using
the `x-personalos-e2e-native-auth-nonce` header. The route is disabled when the
nonce is absent, is never registered by production startup, and exists only so
a development client can exercise the real authenticated mobile boundary
without embedding a bearer token.

For deterministic provider simulation, copy `state` from that URL into the
normal callback route:

- authorize: `GET /v1/health/connection-authorizations/callback/:provider?state=…&code=authorization_code_e2e_success`
- deny: `GET /v1/health/connection-authorizations/callback/:provider?state=…&error=access_denied`

To qualify durable retry, add
`x-personalos-e2e-fail-domain-commit-once: true` to one callback. The E2E host
strips this header before invoking the production API, fails exactly one state
commit, retains the secret-free dispatch, and retries it through the normal
ticket status route. This control does not exist in any production request
schema or production startup path.

`bun run --cwd packages/apps/personalos-api test:operations-rehearsal` runs a
bounded loopback performance and capacity rehearsal through the same executable
host. It evaluates a 750 ms local-loopback API p95 ceiling and zero-error
budget plus steady, burst, injected
dependency-failure, and recovery scenarios with the governed
`personal-operations` qualifier. This is local E2E evidence only: it does not
replace representative devices, production RUM, soak or retry-storm tests,
managed dependency failure, cost validation, or production canaries.

## Life-admin channel effects

`createPersonalCalendarEffectExecutor` and
`createPersonalNotificationEffectExecutor` execute leased life-admin outbox
effects for the worker. Both check the subject's `life_admin` activation
before the encrypted aggregate is loaded (`loadGatedLifeAdminEffectState`;
`createLifeAdminEffectStateLoader` binds the encrypted store). Calendar
`calendar_reconciliation` effects write back to the subject's own active,
read-write provider connection resolved by the deployment host, pass the
effect idempotency key as the provider request id, and report a provider
error as `indeterminate` for reconciliation before any retry; declines are
refused. Mail and in-app `notification_delivery` effects are routed through
the CommunicationOS product producer: email only with PersonalOS email
consent, otherwise the in-app terminal, and push is refused. A notification
whose `scheduledAt` is still in the future returns
`{ status: 'deferred', availableAt }` without admitting anything; the worker
must release the lease with that `availableAt` rather than acknowledge it.
Without a calendar host or CommunicationOS host every effect fails closed.


## Declared capabilities

This manifest does not declare a capability catalogue. Assess the package using its guide, import map and source.

## Canonical imports

Import paths and symbols below are catalogue declarations. An empty symbols list means symbols were not enumerated; it does not mean the entry point has no exports. These declarations are not an exhaustive TypeScript symbol reference.

```json
[]
```

## Declared export entry points

Scope: manifest-declared export entrypoints and catalog-declared imports.

Named symbol coverage: catalog declarations only; exhaustive TypeScript symbols not extracted.

Installation status: not verified.

- `@lssm-tech/app.personalos-api` — subpath `.`
  - `unconditional`: `./src/index.ts` — [pinned source](https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/personalos-api/src/index.ts); verified source file.

## Package publication metadata

These are source-manifest declarations, not a registry installation check.

```json
{
  "types": null,
  "files": null,
  "publishExports": null
}
```

## Dependencies

Metadata status: complete pinned manifest.

### Runtime dependencies

- [@lssm-tech/bundle.personal-os](https://lssm.co/docs/packages/bundle.personal-os/): `workspace:^`
- [@lssm-tech/integration.personal-os-state-postgres](https://lssm.co/docs/packages/integration.personal-os-state-postgres/): `workspace:^`
- [@lssm-tech/integration.provider-database](https://lssm.co/docs/packages/integration.provider-database/): `workspace:^`
- [@lssm-tech/lib.contracts-integrations](https://lssm.co/docs/packages/lib.contracts-integrations/): `workspace:^`
- [@lssm-tech/lib.notification](https://lssm.co/docs/packages/lib.notification/): `workspace:^`
- [@lssm-tech/lib.personal-finance-runtime](https://lssm.co/docs/packages/lib.personal-finance-runtime/): `workspace:^`
- [@lssm-tech/lib.personal-finance-spec](https://lssm.co/docs/packages/lib.personal-finance-spec/): `workspace:^`
- [@lssm-tech/lib.personal-health-runtime](https://lssm.co/docs/packages/lib.personal-health-runtime/): `workspace:^`
- [@lssm-tech/lib.personal-health-spec](https://lssm.co/docs/packages/lib.personal-health-spec/): `workspace:^`
- [@lssm-tech/lib.personal-os-runtime](https://lssm.co/docs/packages/lib.personal-os-runtime/): `workspace:^`
- [@lssm-tech/lib.personal-os-spec](https://lssm.co/docs/packages/lib.personal-os-spec/): `workspace:^`
- [@lssm-tech/module.personal-life-admin](https://lssm.co/docs/packages/module.personal-life-admin/): `workspace:^`
- `elysia`: `catalog:server`

### Peer dependencies

No declarations in the inspected manifest.

### Optional dependencies

No declarations in the inspected manifest.

### Development dependencies

- [@lssm-tech/integration.authos-better-auth](https://lssm.co/docs/packages/integration.authos-better-auth/): `workspace:^`
- [@lssm-tech/integration.personal-os-authos](https://lssm.co/docs/packages/integration.personal-os-authos/): `workspace:^`
- [@lssm-tech/module.personal-household](https://lssm.co/docs/packages/module.personal-household/): `workspace:^`
- [@lssm-tech/module.personal-operations](https://lssm.co/docs/packages/module.personal-operations/): `workspace:^`
- [@lssm-tech/tool.typescript](https://lssm.co/docs/packages/tool.typescript/): `workspace:*`
- `@types/bun`: `catalog:types`
- `better-auth`: `1.7.5`
- `typescript`: `catalog:`

### Peer dependency metadata

```json
{}
```

### Bundled dependencies

```json
null
```

## Package scripts

Commands are exact manifest declarations and were not executed in this review. Script metadata status: complete pinned manifest.

```json
{
  "build": "bun build --target node --packages bundle --outdir dist src/index.ts src/server.ts",
  "dev": "bun run --watch src/server.ts",
  "lint:check": "node ../../../scripts/biome.cjs check .",
  "lint:fix": "node ../../../scripts/biome.cjs check --write .",
  "migrate": "bun run scripts/migrate.ts",
  "migrate:rehearse": "bun run scripts/rehearse-migrations.ts",
  "start": "bun run src/server.ts",
  "start:e2e": "bun run src/e2e-server.ts",
  "test": "bun test --timeout 15000 $(find src -name '*.test.ts' ! -name 'e2e-operations-rehearsal.test.ts' -print)",
  "test:operations-rehearsal": "bun test src/e2e-operations-rehearsal.test.ts",
  "typecheck": "tsgo --noEmit"
}
```

## Declared documentation links

No additional documentation links are declared in the inspected catalogue.

## Existing agent-guide projection

```json
{
  "path": "packages/apps/web-landing/public/llms-packages/app.personalos-api.txt",
  "route": "/llms/app.personalos-api",
  "sourceUrl": "https://github.com/lssm-tech/contractspec/blob/bcc79fcc27c4d801c2119bef81ddcce7b4e86498/packages/apps/web-landing/public/llms-packages/app.personalos-api.txt",
  "blobSha": "b12259c5ef0337315eb8ac8aad73130c3ea4a6a9",
  "sourcePin": "bcc79fcc27c4d801c2119bef81ddcce7b4e86498",
  "bodyEqualsReadme": true,
  "aggregateSourcePath": "packages/apps/web-landing/public/llms-full.txt",
  "aggregateBlobSha": "691b1d33efee24c440598b9106c81432f56aafaf"
}
```
