Import
Import brings local work history into the RECENT tier, where DREAM turns it into daily summaries.
Sources
| Source id | Label |
|---|---|
shell | Shell history |
claude-code | Claude Code |
kiro | Kiro |
cursor | Cursor |
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
GET /api/v1/import/sources— list sources withenabledandsince_days.PUT /api/v1/import/settings— enable a source:{"sources":{"shell":{"enabled":true,"since_days":7}}}(since_days1–365).POST /api/v1/import/preview— dry run. Returns counts, rejected indexes with reasons and up to 5 masked sample items. Writes nothing.POST /api/v1/import/commit— writes accepted items (RECENT tier, tagsimported,src:<source>,kind:<kind>). Returns a job.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"}
}| Field | Rule |
|---|---|
source | Must equal the request source |
text | Required, non-empty, max 8000 characters |
ts | Required ISO 8601; not more than 24 h in the future |
kind | One of command, message, note, file_event (default message) |
meta | String-to-string map, max 2048 bytes |
source_id | Optional, 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 assecret_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).