Import

Import brings local work history into the RECENT tier, where DREAM turns it into daily summaries.

Sources

Source idLabel
shellShell history
claude-codeClaude Code
kiroKiro
cursorCursor

Parsing happens on your machine: a client reads local history and sends normalized items to the API. The server never reads your disk. Every source is off until you enable it.

Flow

  1. GET /api/v1/import/sources — list sources with enabled and since_days.
  2. PUT /api/v1/import/settings — enable a source: {"sources":{"shell":{"enabled":true,"since_days":7}}} (since_days 1–365).
  3. POST /api/v1/import/preview — dry run. Returns counts, rejected indexes with reasons and up to 5 masked sample items. Writes nothing.
  4. POST /api/v1/import/commit — writes accepted items (RECENT tier, tags imported, src:<source>, kind:<kind>). Returns a job.
  5. GET /api/v1/import/jobs/{job_id} — job status and counters.

Item shape

{
  "source": "shell",
  "ts": "2026-10-10T09:15:00Z",
  "text": "git commit -m 'fix billing'",
  "kind": "command",
  "source_id": "optional-stable-id",
  "app": "zsh",
  "project": "billing",
  "meta": {"cwd": "~/code/billing"}
}
FieldRule
sourceMust equal the request source
textRequired, non-empty, max 8000 characters
tsRequired ISO 8601; not more than 24 h in the future
kindOne of command, message, note, file_event (default message)
metaString-to-string map, max 2048 bytes
source_idOptional, max 256 characters; improves de-duplication

Limits

  • Max 500 items per request and 1 MB body (413 otherwise).
  • 20 commits per minute and 50,000 items per day (429 with Retry-After).
  • Commit accepts idempotency_key (8–80 chars); repeating it within 24 h returns the earlier job.

What is filtered

  • Secrets are redacted server-side with the secret guard ([REDACTED:<kind>]). An item that is only a secret is rejected as secret_only.
  • Deny-list: items from password managers and some employer content are dropped, never stored, and only counted as skipped_denylist.
  • Duplicates (same user, source, id or timestamp, and text) are skipped.
  • Rejection reasons: bad_item, empty, too_long, bad_ts, secret_only.

Errors use {"error":{"code","message"}}. Codes: bad_request, too_large, source_not_enabled (403), rate_limited (429), not_found (404).