# Give your persistent personal agent a Chert identity

**Temporary integration path — reviewed October 23, 2026.** This page helps a
one-time coding integrator connect a personal-agent product such as OpenClaw,
Hermes, or Muse to the currently published Chert packages. The coding agent is
not the product. Until a universal personal-agent CLI is released, the wrapper
described here is generated locally for one project.

[CLI quickstart](https://docs.trychert.com/facetime-cli/quickstart) ·
[Personal-agent operations guide](https://docs.trychert.com/facetime-cli/personal-agent) ·
[FaceTime CLI reference](https://docs.trychert.com/facetime-cli/commands)

> **Important:** Package help, scaffold, and local fixture/loopback checks have
> passed. A live shared-line allocation and a complete real message/call flow
> have not been verified. Do not claim that a line is assigned, a message was
> delivered, or a call works until the service confirms it and the owner
> explicitly verifies the real-world result.

## What works today

| Surface | Available | Not provided or not verified |
| --- | --- | --- |
| `@trychert/facetime@beta` | `login`, `onboard`, `new`, `doctor`, `dev`, and `guide fix`. `dev` is a foreground connector for incoming FaceTime calls to an eligible line. | A universal personal-agent plugin, always-on host, or verified live line allocation. `new` creates a generic LiveKit starter; it does not integrate OpenClaw, Hermes, Muse, or another personal-agent runtime. |
| `@trychert/sdk@0.1.0` | `context`, iMessage `send`, and FaceTime `status`, `lines`, and `workers`. | iMessage inbox/watch/receive, FaceTime outbound call start/watch/end, media relay, automatic shared-line allocation, or a unified cross-channel identity. |
| Generated local wrapper | You may have an integrator create `setup`, `start`, `health`, `message`, `call`, `status`, `watch`, and `stop`. | Those wrapper commands are not Chert commands. `call` and iMessage `watch` must fail closed as pending capabilities. A local `watch` may only relay events from its own running `chert dev --json` process. |

The iMessage API key, FaceTime token, Chert CLI login, and LiveKit credentials
are separate credentials. `CHERT_PROJECT_ID` is context; it does not combine
or authorize those services. There is no Chert-managed owner-contact allowlist
or cross-channel consent policy. The personal-agent application must enforce
the owner's approved contact policy locally.

## Prerequisites and safe install

- A macOS or Linux host; native Windows is unsupported.
- Node.js 22.12+ (22.x), 24.x, or 26.x for the CLI when using npm/pnpm/npx;
  the bundled starter supports Node 22.23.2 or 24.x. Bun 1.4.0 package commands
  were exercised locally.
- An owner-approved Chert project, or explicit approval to start new onboarding.
- For voice, the owner's existing LiveKit project and a registered named agent.
- The owner available to complete browser and phone verification when requested.
- Explicit owner approval before connecting an inbound-call line or sending any
  real message/call.

Install the current CLI beta and the published SDK in the project directory:

```bash
npm install @trychert/facetime@beta @trychert/sdk@0.1.0
pnpm add @trychert/facetime@0.1.0-beta.10 @trychert/sdk@0.1.0
bun add @trychert/facetime@beta @trychert/sdk@0.1.0
npx --yes --package @trychert/facetime@beta chert --help
bunx --yes --package @trychert/facetime@beta chert --help
npx --yes --package @trychert/sdk@0.1.0 chert-sdk --help
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk --help
```

At review, npm's `beta` tag pointed to beta.10 while `latest` pointed to beta.6.
Use `@beta` intentionally in npm/Bun commands; do not omit the tag. The tested
`pnpm add @trychert/facetime@beta` resolved beta.6, so the pnpm example pins
beta.10 explicitly. Pin the reviewed version for repeatable releases. The
`npx`/`bunx` commands above run the published binaries without putting secrets
in command arguments.

Discover supported flags before use:

```bash
bunx --yes --package @trychert/facetime@beta chert login --help
bunx --yes --package @trychert/facetime@beta chert onboard --help
bunx --yes --package @trychert/facetime@beta chert new --help
bunx --yes --package @trychert/facetime@beta chert doctor --help
bunx --yes --package @trychert/facetime@beta chert dev --help
bunx --yes --package @trychert/facetime@beta chert guide fix
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk --help
```

## Setup and line selection

For an existing project, use `login`. It opens a browser so the owner can
approve this computer for one project. Do not paste browser tokens, passwords,
or device codes into the agent's chat or logs.

```bash
bunx --yes --package @trychert/facetime@beta chert login
```

For a new project only, begin onboarding after the owner approves the
verification exchange. `--skip-demo` avoids requesting the hosted FaceTime
demo; onboarding may still ask the owner to complete browser setup and send a
verification iMessage from their own phone. Stop and let the owner do those
steps. Never send the code for them or report verification as complete while
the command is pending.

```bash
bunx --yes --package @trychert/facetime@beta chert onboard --skip-demo --no-browser --json --wait 0
```

`--wait 0` reports pending progress and exits (pending verification uses exit
code 3). Preserve `~/.chert` or the configured `CHERT_HOME`, then resume the
same onboarding request after the owner completes verification. Do not run a
second onboarding or use `--restart` to recover an uncertain result. The
implementation has an onboarding/allocation flow, but current local E2E did
not complete live phone verification or confirm a live allocated line; capacity
and ownership must be checked from the actual response.

The SDK can inspect existing access, but it does not assign a line:

```bash
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk context
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk facetime status
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk facetime lines
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk facetime workers
```

Choose only the project and line the owner approved. `facetime status` is an
identity/status read, not proof of audio/video readiness. A healthy `doctor`
result also does not prove a real call works.

## Voice agent and temporary project wrapper

If the owner asks for a new voice-agent starter, run `new` with a **new child
directory**. It refuses an existing target and creates a generic LiveKit voice
agent, not a personal-agent integration. Keep the owner's existing runtime if
one already exists.

```bash
bunx --yes --package @trychert/facetime@beta chert new personal-agent
```

The starter's help describes `npm install` and `npm start`; the end-to-end
rehearsal did not validate a real agent start or live media. Review the
generated files and dependencies before running them. The starter's
`.env.local` must remain local, be ignored by Git, and have mode `0600`.

An integrating coding agent may create a project-local wrapper with these
contracts. These are **generated project commands**, not Chert CLI commands:

| Wrapper command | Contract |
| --- | --- |
| `setup` | Read only the owner's explicit brief and relevant project files. Preview planned files and behavior; wait for approval before writing or starting account/verification flows. Reuse the selected project, assigned line, and existing LiveKit environment. |
| `start` | Start the owner's existing personal-agent runtime and, after an explicit approval to receive calls, start foreground `chert dev --agent NAME --json`. This is not an always-on service. |
| `health` | Run read-only `chert doctor --json` and SDK identity/line/worker reads. Do not use `doctor --agent` unless the owner approves a real test job. Report identity separately from media readiness. |
| `message` | Require fresh approval of the exact recipient and body, then use `chert-sdk imessage send` with a stable idempotency key. A `queued` receipt does not mean sent or delivered. |
| `call` | Return a structured `capability_pending` result for outbound calls. There is no published SDK method to start a FaceTime call. Do not invent a route or silently substitute a real call. |
| `status` | Report read-only SDK status/lines/workers and local process state. Do not label identity as call readiness. |
| `watch` | May relay structured events from its own running `chert dev --json` process for incoming FaceTime activity. There is no SDK iMessage inbox watcher or remote FaceTime call watch API. |
| `stop` | Send one SIGINT to wrapper-owned `chert dev`, then wait for confirmed binding release. `release_failed` or retained cleanup is not a release. This does not unassign the phone number/shared allocation. |

`chert dev --json` emits newline-delimited JSON records with `schema_version: 1`
and `command: "dev"`. Call events include `call_incoming`, `call_accepted`,
`call_declined`, `call_ended`, `call_media`, and `call_bridge_ready`. The last
means Chert wrote the bridge-ready room signal; it is not proof that audio/video
worked or that the caller heard the agent. Session records include `dev_ready`,
`dev_stopped`, `cleanup_pending`, and `release_failed`. The first Ctrl+C begins
graceful drain and release. A second interrupt reports that release is still in
progress; a third can exit without releasing. Never report the connector
released unless the terminal record confirms it.

The Chert CLI does not install or supervise the personal agent. A personal
platform may have its own service manager, but automatic restart, always-on
operation, and recovery after host reboot have not been validated for this
integration. Preserve `~/.chert`; persist only non-secret project/line/agent
identifiers and request IDs. On restart, report existing state and health—do
not replay outbound messages or calls automatically.

## Secrets, messages, calls, and confirmation

The SDK CLI uses separate service configuration. The JavaScript library receives
its endpoint and key through `ChertClient` construction; it does not automatically
load these CLI environment variables:

| Purpose | Environment variable names |
| --- | --- |
| iMessage SDK CLI | `CHERT_BASE_URL`, `CHERT_API_KEY`; `CHERT_PROJECT_ID` for application context |
| FaceTime SDK CLI reads | `CHERT_FACETIME_URL`, `CHERT_FACETIME_TOKEN`; `CHERT_PROJECT_ID` for application context |
| LiveKit agent | `LIVEKIT_URL`, `LIVEKIT_API_KEY`, `LIVEKIT_API_SECRET`, `AGENT_NAME`; the starter also uses `OPENAI_API_KEY` |

Never print, echo, log, screenshot, commit, or send these values to an agent
prompt. Do not place secrets in command-line arguments. Have the owner enter
them locally into `.env.local` or the platform's private secret store; ensure
the file is ignored by Git and mode `0600`. For diagnostics, report only whether
each required variable is present and redact all values.

Before every real outbound message or call, show the exact recipient and
message/purpose, note any expected cost or disclosure, and get a new explicit
confirmation. Setup approval is not send/call approval. Do not use real
contacts for smoke tests.

An explicitly approved iMessage send uses:

```bash
bunx --yes --package @trychert/sdk@0.1.0 chert-sdk imessage send \
  --phone "$APPROVED_E164" \
  --body "$APPROVED_MESSAGE" \
  --idempotency-key "$STABLE_REQUEST_ID"
```

The response is a strict HTTP 202 `queued` receipt—not proof of delivery. The
SDK does not automatically retry. If the result times out or is uncertain, do
not send again automatically. Preserve the same idempotency key and reconcile
the original request with the service/operator first. The published SDK has no
generic iMessage receive/watch command.

For FaceTime, `chert dev` connects an existing LiveKit agent to receive calls
on an eligible line. It is a foreground process; starting it can make the line
available to incoming callers, so obtain owner approval first. The SDK has no
outbound FaceTime call-start/watch/end method. Do not infer working audio or
video from login, line status, or worker status.

## Structured output, recovery, and cleanup

Use `--json` for CLI records. The generated wrapper should emit its own versioned
JSON Lines contract, keep Chert JSON/events intact, and never parse human prose
as a success signal. Keep the wrapper's schema distinct from Chert's output.

| Result/state | Safe response |
| --- | --- |
| `login_required` | Pause for the owner to sign in and select the intended project. Never request a token in chat. |
| `forbidden` | Check `chert whoami`; ask the project owner/admin to grant the correct role. |
| `line_in_use`, `line_in_call` | Wait for the current holder/call. Do not use takeover without explicit admin approval. |
| `line_paused`, `shared_line_paused`, `shared_allocation_inactive`, `worker_unavailable` | Stop and ask the owner/admin to resolve readiness. Preserve onboarding state; do not create another allocation or force a call. |
| `cleanup_pending`, `release_failed` | Stop new calls; preserve state and ask the owner/admin to confirm cleanup. |
| `unconfirmed_text_outcome` | Do not retry automatically. Reconcile using the original idempotency key. |

Start diagnosis with:

```bash
bunx --yes --package @trychert/facetime@beta chert guide fix
bunx --yes --package @trychert/facetime@beta chert doctor --json
bunx --yes --package @trychert/facetime@beta chert onboard --status --json
```

Capture timestamps, command, project/line IDs only when safe, error codes, and
redacted event records. Remove phone numbers, message bodies, tokens, credential
URLs, `.env.local`, raw process environments, and provider responses from logs.

To stop the connector, send one Ctrl+C/SIGINT and wait for confirmed binding
release. That stops the active connector session; it does not unassign the
allocated number or project line. `release_failed` is not proof of release, and
there is no verified line-allocation release command; ask the project owner/admin.

## Ready-to-paste integration prompt

```text
You are a one-time coding integrator. My product is my persistent personal
agent (such as OpenClaw, Hermes, or Muse), not you. Integrate only what the
current published Chert packages actually support.

First inspect the target directory and relevant project files. If the target
is not empty, propose an additive plan and do not overwrite files. If it is
empty, show me the planned files, commands, and behavior, then wait for my
approval before writing. Derive persona, handlers, and owner-contact policy
only from my explicit brief and relevant repository. Do not mine unrelated
conversation, secrets, or hidden files for behavior.

Use `@trychert/facetime@beta` for the existing `login`, `onboard`, `new`,
`doctor`, `dev`, and `guide fix` CLI commands. Use `@trychert/sdk@0.1.0` only
for its existing iMessage send and FaceTime context/status/lines/workers
surface. Inspect command help before use. Keep service credentials separate.
Do not claim that the SDK can receive/watch iMessages or start/watch/end an
outbound FaceTime call.

Install in the project with `bun add @trychert/facetime@beta @trychert/sdk@0.1.0`.
The beta tag can move; pin and review the exact version for repeatable use.

Generate a local `chert-agent` wrapper exposing `setup`, `start`, `health`,
`message`, `call`, `status`, `watch`, and `stop`. These are local wrapper
commands, not Chert commands. `call` must return a structured pending result.
`watch` may only relay events from the wrapper's own `chert dev --json`
process; report iMessage watch as pending. `start` is foreground unless a
user-approved personal-agent platform service manager is implemented; do not
promise always-on/restart recovery.

Reuse the owner's intended Chert project, line, and LiveKit environment. Use
`login` for an existing project. Begin `onboard --skip-demo` only after I
approve account creation and the verification exchange; stop while I complete
browser/phone steps myself. Preserve `~/.chert` and resume the same onboarding
after uncertain results. Do not claim a line is assigned until the service
actually confirms it and I verify the result.

Before writing `.env.local`, add it to `.gitignore`, preview the file plan, and
create it with mode 0600. I will enter LiveKit/OpenAI/Chert secrets locally.
Never print, echo, log, transmit, screenshot, commit, or ask me to paste a
secret into chat. Persist only non-secret project/line/agent identifiers and
stable request/idempotency keys. Never replay an outbound side effect after a
restart.

Require fresh explicit confirmation immediately before every real outbound
message or call, showing the exact recipient and content/purpose. A queued
message is not delivery; do not retry an uncertain send automatically. Ask
before starting `dev`, because it connects the agent to incoming FaceTime
calls. Run read-only `doctor --json` first; do not use `doctor --agent` without
approval for a real test job. Preserve structured output, redact logs, stop
on readiness or cleanup errors, and clearly list all pending capabilities.
Ctrl+C stops the active connector session but does not release the phone-number
or project allocation.
```
