ente-cli 0.1.0 → 0.4.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,274 @@
1
+ # ente CLI
2
+
3
+ Command-line interface for [ente](https://github.com/valentindoering/ente) — a
4
+ relationship manager and knowledge graph (people, orgs, projects, topics and the
5
+ notes/calls/tasks/conversations logged against them).
6
+
7
+ TypeScript, built on [clipanion](https://clipanion.dev/), bundled with esbuild
8
+ into a single self-contained file, published to npm and Ivo's Gitea npm registry. It talks
9
+ to ente's external REST API (`/api/external/*`) with a static Bearer API key.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm i -g ente-cli
15
+ # Ivo's registry remains available with the same package and version:
16
+ npm i -g ente-cli --registry https://gitea.i.ivo-zilkenat.de/api/packages/ivo.zilkenat/npm
17
+ ```
18
+
19
+ ## Setup
20
+
21
+ Connect a normal CLI profile with browser approval. Replace the site URL and
22
+ email with your Ente deployment and account:
23
+
24
+ ```bash
25
+ ente auth pair --url https://your-deployment.convex.site --email you@example.com
26
+ ```
27
+
28
+ The CLI prints a review link and six-digit code. Open the link, sign in, inspect
29
+ the requested profile, enter the code, and approve it. The CLI generates its
30
+ key locally and sends its hash and short prefix to Ente. The full key stays
31
+ local and never appears in the browser or terminal output. Keep the CLI running
32
+ until it verifies the new profile.
33
+
34
+ To connect an operator to one agent, use that agent's ID from `ente agent list`
35
+ and name the local profile:
36
+
37
+ ```bash
38
+ ente auth pair --url https://your-deployment.convex.site --email you@example.com \
39
+ --profile mail-operator --agent <agent-id> --access write
40
+ ```
41
+
42
+ For up to ten operators, put the exact agent IDs and local profile names in a
43
+ JSON file outside a repository:
44
+
45
+ ```json
46
+ [
47
+ { "profile": "operator-a", "agentId": "<agent-id-a>", "access": "write" },
48
+ { "profile": "operator-b", "agentId": "<agent-id-b>", "access": "read" }
49
+ ]
50
+ ```
51
+
52
+ ```bash
53
+ ente auth pair --url https://your-deployment.convex.site --email you@example.com \
54
+ --manifest /private/path/operators.json
55
+ ```
56
+
57
+ One Ente approval page lists all profiles and scopes. Existing local profiles
58
+ are never overwritten unless `--replace` is supplied. A stopped or expired CLI
59
+ run must be started again. Pending requests expire after ten minutes.
60
+ Both agent access modes can read and change Ente data and manage spaces.
61
+ With `read`, the key can inspect the bound agent and inbox, mark inbox threads
62
+ read/unread, and change their workflow state. `write` also permits agent
63
+ changes and sending email. The CLI saves approved profiles before
64
+ activating their keys, so a failed local save cannot leave active keys behind.
65
+
66
+ For headless integrations or a legacy key, generate an API key in the web app
67
+ and enter it directly in the terminal:
68
+
69
+ ```bash
70
+ ente auth login --url https://your-deployment.convex.site --key-stdin
71
+ ```
72
+
73
+ Credentials are stored at `~/.config/ente/config.toml` (`~/Library/Application
74
+ Support/ente/config.toml` on macOS), `0600`. `ENTE_API_URL` and `ENTE_API_KEY`
75
+ override the file only when both are set.
76
+
77
+ An agent operator profile is bound to that agent's configuration, threads,
78
+ scheduled runs, and inbox when enabled:
79
+
80
+ ```bash
81
+ ENTE_PROFILE=mail-operator ente agent config show
82
+ ENTE_PROFILE=mail-operator ente agent mail threads --unread
83
+ ```
84
+
85
+ Operator keys use the CLI's scoped REST commands. They cannot be exchanged for
86
+ the legacy full-account CLI session token, so the bound-agent restriction
87
+ cannot be bypassed through direct Convex commands. Use a normal account key for
88
+ legacy administrative CLI commands that require that session token.
89
+
90
+ Named profiles are optional. Use one only when a person or process deliberately
91
+ switches between several credentials. `--profile` overrides `ENTE_PROFILE`.
92
+ Profiles do not activate from the current directory and are not a security
93
+ boundary. Use a separate OS account or container when operators on the same
94
+ machine must not read each other's keys. Never commit a key or put it in a
95
+ project `.env` file.
96
+
97
+ ## Usage
98
+
99
+ ```bash
100
+ ente search "Alice"
101
+ ente entity list --type person
102
+ ente entity rename "Lorey Georg" "Georg Lorey"
103
+ ente task list --due today
104
+ ente activity create --type note --title "Meeting notes" --entity "Alice" --space "Personal"
105
+ ente activity get <activityId> --json # includes the body, nested agenda, messages/replies, entities, and attachments
106
+ ente agenda create-point --meeting <meetingActivityId> --title "Decisions" --content="- Ship the smaller scope"
107
+ ente agenda link-task --point <agendaPointId> --task "#12"
108
+ ente activity message add <activityId> --content "Decision: ship the smaller scope first."
109
+ ente activity content read <activityId> --json
110
+ ente activity content edit <activityId> --expected-version 42 --operations-file edits.json --json
111
+ ente canvas boards <entityId>
112
+ ente canvas html create <boardId> --title "Prototype" --file ./prototype.html --operation-id prototype-v1
113
+ ente notification send --subject "Weekly brief" --text "Your brief is ready." --html-file ./brief.html --attachment ./brief.pdf --inline-image chart=./chart.png
114
+ ente agent config show
115
+ ente agent threads
116
+ ente agent mail threads --unread
117
+ ente agent mail send --to person@example.net --subject "Update" --text "Plain fallback" --attachment ./handoff.md --html "<p><strong>Update</strong></p>" --idempotency-key agent-update-2026-09-01
118
+ ente tasks
119
+ ente guide # concepts; `ente guide <topic>`: entities, tasks, activities, search, patterns, limits
120
+ ```
121
+
122
+ Every command supports `--json`. Run `ente --help` or `ente <group> --help`.
123
+
124
+ ### Command groups
125
+
126
+ | Group | Commands |
127
+ |---|---|
128
+ | `auth` | `pair`, `login`, `status`, `logout`, `profiles` |
129
+ | `entity` | `list`, `create`, `get`, `update` (`--name`, `--tag`, `--description`), `rename`, `archive`, `restore` (`--share-parents` plus the returned grant fingerprint), `pin` (`--role`, optional confirmed parent grants), `unpin`, `add-to-space`, `remove-from-space` (`--remove-from-activities` optional) |
130
+ | `activity` | `list`, `create`, `search`, `get`, `update`, `delete`, `restore`, `message add`, `attachment upload` |
131
+ | `agenda` | `create-point`, `link-task` |
132
+ | `task` | `list`, `get`, `create`, `update`, `done`, `assign`, `unassign`, `set-assignees`, `clear-assignees` |
133
+ | `pins` | `list` |
134
+ | `space` | `members` |
135
+ | `recording` | `list`, `show`, `inspect`, `rerun` (admin only) |
136
+ | `canvas` | `boards`, `html list`, `html get`, `html create`, `html update`, `html delete` |
137
+ | `notification` | `send` (emails only your own Ente account address; optional HTML, file attachments, and CID inline images) |
138
+ | `agent` | `list`, `threads`, `show`, `new`, `send`, `config show`, `config set-prompt`, `schedules configure` |
139
+ | `agent mail` | `address`, `threads`, `show`, `send`, `reply`, `mark` |
140
+ | top-level | `search`, `ask`, `query`, `tasks`, `guide` |
141
+
142
+ ### Agent operators and inboxes
143
+
144
+ An agent operator key can read and change Ente data, manage spaces, and access
145
+ one bound agent. Agent read includes Ente configuration such as the prompt,
146
+ Ente thread history, scheduled-run configuration, inbox reads, and thread status
147
+ updates when an inbox is active. Agent
148
+ write additionally allows prompt changes, full scheduled-run replacement, and
149
+ inbox send/reply. New write-capable keys also receive `agent:communicate`, which
150
+ lets the bound external agent start, claim, and reply to external threads without
151
+ calling an Ente-hosted model. Ente prompt and scheduled runs configure the Ente agent
152
+ counterpart; they are not instructions or schedules for the external operator.
153
+ The caller cannot select another agent, mailbox, or sender.
154
+ The corresponding scopes are `agent:read`, `agent:write`, `mail:read`, and
155
+ `mail:send`, and `agent:communicate`.
156
+
157
+ The inbox owner must add each exact correspondent in Ente. Unlisted inbound
158
+ mail stays owner-only and never appears in operator REST, MCP, WebMCP, or CLI
159
+ reads. New sends and replies are rejected before persistence unless the final
160
+ recipient is allowed. An administrator-granted unlimited-mail account may
161
+ enable send-to-anyone or receive-from-anyone separately for each mailbox.
162
+
163
+ ```bash
164
+ ente agent config show
165
+ ente agent threads --include-archived --limit 20
166
+ ente agent show <ente-thread-id>
167
+ ente agent new "Can I publish this?" --title "Release note" --request text --idempotency-key release-question-1
168
+ ente agent threads --attention agent
169
+ ente agent send <ente-thread-id> "Published." --request ack --request-prompt "Release note published" --idempotency-key release-answer-1
170
+ ente agent config set-prompt --text "Review finance updates."
171
+ ente agent config set-prompt --file ./ente-agent-prompt.md
172
+ ente agent schedules configure --file ./schedules.json
173
+ ente agent mail address
174
+ ente agent mail threads --unread --limit 20
175
+ ente agent mail show <thread-id>
176
+ ente agent mail send --to person@example.net --subject "Update" --text "Plain fallback" --html "<p>Rich update</p>" --attachment ./reference.pdf --idempotency-key update-2026-09-01
177
+ ente agent mail reply <thread-id> --message <message-id> --text-file ./reply.txt --html-file ./reply.html --attachment ./handoff.docx --idempotency-key reply-2026-09-01
178
+ ente agent mail mark <thread-id> --state-version 4 --handled
179
+ ```
180
+
181
+ `schedules.json` is the complete replacement list. Omitted schedules are
182
+ deleted:
183
+
184
+ ```json
185
+ [
186
+ {
187
+ "enabled": true,
188
+ "prompt": "Review new finance mail and prepare follow-ups.",
189
+ "timeMinutes": 480,
190
+ "timezone": "Europe/Berlin"
191
+ }
192
+ ]
193
+ ```
194
+
195
+ Send and reply support repeatable `--inline-image CONTENT_ID=PATH` alongside
196
+ `--attachment PATH`. Supply HTML containing `<img src="cid:readiness">` and
197
+ `--inline-image readiness=./readiness.png`. The CLI embeds local file bytes in
198
+ the email; use CID images for private charts, never remote URLs or data URIs.
199
+ Inline images must be PNG, JPEG, GIF, or WebP (verified by file signature).
200
+ Content-IDs must be unique, case-sensitive, at most 128 characters, start with a
201
+ letter or number, and contain only letters, numbers, `.`, `_`, `@`, or `-`.
202
+ Every inline image must have a matching HTML CID reference, and every CID
203
+ reference must have an image. Keep the complete report in the required plain-text
204
+ fallback; HTML and images do not replace it.
205
+
206
+ The combined limit is **four files** across ordinary attachments and inline
207
+ images, **750,000 bytes per file** (3,000,000 decoded bytes total). Four Health
208
+ charts fit only when no ordinary attachment is also sent. Five SaaS Spending
209
+ charts exceed this limit and are rejected; inline images do not bypass it.
210
+ For example:
211
+
212
+ ```bash
213
+ ente agent mail send --to owner@example.net --subject "Readiness" --text-file ./report.txt --html-file ./report.html --inline-image readiness=./readiness.png --idempotency-key readiness-report-v1
214
+ ente agent mail reply <thread-id> --message <message-id> --text-file ./report.txt --html-file ./report.html --inline-image readiness=./readiness.png --attachment ./notes.txt --idempotency-key readiness-reply-v1
215
+ ```
216
+
217
+ Retries must keep filenames, MIME types, Content-IDs, file order, and exact file
218
+ bytes unchanged, along with the recipient, text, HTML, and reply target. A changed
219
+ image or CID with the same key is rejected. Reported `sent` means transport
220
+ accepted the message; delivery feedback may later report delivered, delayed,
221
+ bounced, or complained. An unknown delivery outcome must never be retried with a
222
+ new key.
223
+
224
+ `--text` and `--html` accept inline strings. Their `--text-file` and
225
+ `--html-file` counterparts read UTF-8 files. After an ambiguous timeout, retry
226
+ the exact same operation with the same `--idempotency-key`; changing the body,
227
+ recipient, thread, or message requires a new key.
228
+
229
+ ### Operational recipes (playbooks)
230
+
231
+ Copy-pasteable, task-oriented recipes live in [`playbooks/`](./playbooks/) — log a
232
+ meeting, rename/merge an entity, work around cross-space linking, etc. Start there
233
+ for "how do I do X".
234
+
235
+ ## Develop in-repo / build
236
+
237
+ ```bash
238
+ pnpm setup:cli # from the repository root; once per checkout
239
+ cd cli
240
+ pnpm dev entity list # run from source via tsx
241
+ pnpm typecheck # the build-from-truth gate (tsc --noEmit)
242
+ pnpm build # → dist/cli.mjs (+ dist/SKILL.md)
243
+ ```
244
+
245
+ The CLI is not a workspace member. `pnpm setup:cli` installs its locked
246
+ dependencies separately. The repository's `pnpm check` typechecks and tests the
247
+ CLI without installing dependencies.
248
+
249
+ Publishing is automatic: a push to `main` touching `cli/**` or the publish
250
+ workflow selects a version above both registries, tests and packs once, then
251
+ publishes identical bytes to npm and Gitea. npm uses GitHub OIDC; Gitea keeps
252
+ the existing package token. See `.github/workflows/publish-cli.yml` and
253
+ `docs/cli-architecture.md` for setup and retry instructions.
254
+
255
+ ## Architecture
256
+
257
+ ```
258
+ core/ brand-neutral: transport (REST/fetch), config, output, errors, update, command base.
259
+ ente/ branded: the /api/external client, types, resolve, deadline, formatters, commands/*.
260
+ cli.ts clipanion bootstrap: registers every command group.
261
+ ```
262
+
263
+ The dependency direction is one-way — `ente/` imports `core/`, never the reverse.
264
+ See [`CLAUDE.md`](./CLAUDE.md) for the layering rules and conventions.
265
+
266
+ ## Public installation and recovery guide
267
+
268
+ This is the Ente private knowledge-graph / relationship-manager CLI at ente.fast,
269
+ not Ente Photos. Follow https://ente.fast/cli.md for new installations, upgrades,
270
+ PATH conflicts, configuration reuse, legacy API keys, and stale authentication.
271
+ Keep working credentials. `ente auth status --json` reports local configuration
272
+ without key material; verify server access with `ente entity list --limit 1 --json`.
273
+ Use `auth login --key-stdin` for hidden local key entry as shown in the guide.
274
+ Never put secrets in chat, repositories, project `.env` files, or logs.
package/dist/SKILL.md ADDED
@@ -0,0 +1,344 @@
1
+ ---
2
+ name: m:ente-cli
3
+ description: "Cli: drives the ente CRM and knowledge graph over its Convex API as the signed-in user — entities (people, organisations, projects, topics), activities (notes, calls, meetings, tasks), relationships, spaces, full-text and AI-backed search, agent threads and mail, plus Excalidraw canvas prototypes. Use when context about a person, an organisation or a meeting has to be stored, looked up or updated from the shell. Not for splitting shared costs, which is schnorrer-cli."
4
+ when_to_use: "Remembering what was said in a call or meeting; looking up open tasks, deadlines or follow-ups for a person or project; creating or renaming an entity and pinning it to a parent; linking an activity to several entities or moving it between spaces; asking a question over the whole graph and getting citations; reviewing the voice-recording prompt or debugging a failed recording; sending a notification mail or an agent-inbox reply; posting to the in-app feedback board; managing Excalidraw canvas HTML prototypes on an entity board."
5
+ metadata:
6
+ short-description: Relationship memory through ente
7
+ ---
8
+
9
+ # ente-cli - CRM & Relationship Manager CLI Skill
10
+
11
+ ente is a CRM / relationship manager that tracks people, organisations, projects, and topics (entities), and logs notes, calls, tasks, and conversations (activities) against them. This skill wraps the `ente` CLI so an agent can manage entities, activities, tasks, pins, and search end-to-end.
12
+
13
+ ---
14
+
15
+ ## Prerequisites
16
+
17
+ This is Ente’s private knowledge-graph / relationship-manager CLI at ente.fast,
18
+ not Ente Photos. For installation, upgrades, PATH conflicts, and recovery, follow
19
+ https://ente.fast/cli.md. Honor an explicit CLI request even if MCP works;
20
+ otherwise MCP remains the default for ordinary remote access.
21
+
22
+ Reuse an existing working configuration. Never generate another key merely
23
+ because the CLI was upgraded. Check locally, then verify with a read-only call:
24
+
25
+ ```bash
26
+ ente auth status --json
27
+ ente entity list --limit 1 --json
28
+ ```
29
+
30
+ Auth status reports local configuration, not server validity. Only the read
31
+ verifies access. Upgrade older releases if --json prints text.
32
+ If no valid profile exists, run `ente auth pair --url <convex-site-url> --email
33
+ <account-email>`. Open the printed Ente review link for the user and ask them to
34
+ compare and enter the printed six-digit code on that page. Keep the command
35
+ running until it reports verification. The CLI creates the key locally and
36
+ passes its hash and short prefix to Ente. The full key stays local.
37
+ Never collect secrets in chat, repositories,
38
+ project `.env` files, or logs. A legacy key can still be entered with
39
+ `ente auth login --url <convex-site-url> --key-stdin`.
40
+
41
+ The current CLI reuses the legacy config.toml in the platform user configuration
42
+ directory (macOS: ~/Library/Application Support/ente; Linux: ~/.config/ente).
43
+ The complete ENTE_API_URL / ENTE_API_KEY environment pair overrides that file.
44
+ Partial overrides fail closed. Check the selected profile and stale environment
45
+ overrides before replacing credentials. Never print their secret values.
46
+
47
+ For an agent operator, pair a named profile with the exact agent ID and scope.
48
+ For several operators, pass a JSON manifest with up to ten `{ profile, agentId,
49
+ access }` entries. The Ente page shows the complete set for one approval:
50
+
51
+ Both agent access modes can read and change Ente data and manage spaces. With
52
+ `read`, the key can inspect the bound agent and inbox, mark inbox threads
53
+ read/unread, and change their workflow state. `write` also permits agent
54
+ changes and email sending.
55
+
56
+ ```bash
57
+ ente auth pair --url <convex-site-url> --email <account-email> --profile operator-name --agent <agent-id> --access write
58
+ ente auth pair --url <convex-site-url> --email <account-email> --manifest /private/path/operators.json
59
+ ENTE_PROFILE=operator-name ente agent config show --json
60
+ ENTE_PROFILE=operator-name ente agent mail threads --unread --json
61
+ ```
62
+
63
+ Operator keys use scoped REST commands and cannot mint the legacy full-account
64
+ CLI session token. This preserves the one-agent boundary. A normal account key
65
+ is still required for legacy administrative commands that call Convex
66
+ functions directly.
67
+
68
+ Named profiles are optional and only needed to switch deliberately between
69
+ credentials. `--profile` overrides `ENTE_PROFILE`. Profiles do not activate
70
+ from the current directory and do not isolate secrets from other processes
71
+ running as the same operating-system user. Use a separate OS account or
72
+ container when that isolation matters. Never store a key in the repository or
73
+ a project `.env` file.
74
+
75
+ Verify server access with `ente entity list --limit 1 --json`.
76
+
77
+ Install / upgrade the CLI from npm:
78
+ ```bash
79
+ npm i -g ente-cli --registry https://registry.npmjs.org
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Important Notes
85
+
86
+ - **Install targets**: The CLI writes this skill to supported app paths when they exist: `~/.claude/skills/ente-cli/SKILL.md` and `~/.codex/skills/ente-cli/SKILL.md`.
87
+ - **Proactive triggers**: meeting logs, inbox context capture, promise/follow-up tracking, and people/org/project memory updates.
88
+ - **Entity resolution**: Entity names are resolved via fuzzy search. Pass a name or a Convex ID (long alphanumeric string, 20+ chars). If ambiguous, the CLI lists matches and asks for a specific ID.
89
+ - **Space resolution**: Space names work the same way — exact match first, then substring. Use `--space` to target a workspace.
90
+ - **--json flag**: Every command supports `--json`. Always use `--json` when parsing output programmatically.
91
+ - **Deadlines**: stored as millisecond epochs; displayed as `DD.MM.YYYY` / `DD.MM.YYYY, HH:MM` in Europe/Berlin.
92
+ - **Entity types**: `person`, `org`, `project`, `topic`
93
+ - **Activity types**: `note`, `conversation`, `meeting`, `call`, `message`, `task`
94
+
95
+ ---
96
+
97
+ ## Quick Reference
98
+
99
+ ```bash
100
+ # Auth
101
+ ente auth pair --url <convex-site-url> --email <account-email> [--profile <name>] [--agent <agent-id> --access read|write] [--manifest <json-file>]
102
+ ente auth login --url <convex-site-url> --key-stdin
103
+ ente auth status
104
+ ente auth logout
105
+ ente auth profiles
106
+
107
+ # Search & ask
108
+ ente search "Alice" [--type person] [--json]
109
+ ente ask "What's open with Erik?" [--space <name>] [--entity <name>] [--evidence] [--json] # AI answer + citations
110
+ ente query "QM system export" [--space <name>] [--entity <name>] [--verbose] [--json] # evidence only, no AI
111
+
112
+ # Entities
113
+ ente entity list [--query <text>] [--type person|org|project|topic] [--space <name>] [--limit 50] [--archived] [--json]
114
+ ente entity create "Jane Doe" --type person [--pin "Acme Corp"] [--share-parents --parent-space-grant-fingerprint <token>] [--alias "JD"] [--attr email=jane@acme.com] [--tag vip] [--description "CTO at Acme"] [--json]
115
+ ente entity get "Jane Doe" [--json]
116
+ ente entity update "Jane Doe" [--name "Jane A. Doe"] [--alias-add "Jane"] [--alias-remove "JD"] [--attr role=CEO] [--tag vip] [--description "…"] [--json]
117
+ ente entity rename "Lorey Georg" "Georg Lorey" # change display name
118
+ ente entity pin "Jane Doe" "Acme Corp" [--role "student"] [--share-parents --parent-space-grant-fingerprint <token>] [--json]
119
+ ente entity unpin "Jane Doe" "Acme Corp" [--json]
120
+ ente entity add-to-space "Jane Doe" --space "Team" [--share-parents --parent-space-grant-fingerprint <token>] [--json]
121
+ ente entity remove-from-space "Jane Doe" --space "Team" [--remove-from-activities] [--json]
122
+ ente pins list "Jane Doe" [--json] # relationships whose endpoints are accessible
123
+ ente entity archive "Old Project" [--json]
124
+ ente entity restore <entity-id> [--share-parents --parent-space-grant-fingerprint <token>] [--json]
125
+
126
+ # Activities
127
+ ente activity list [--entity "Jane"] [--type note|conversation|meeting|call|message|task] [--attr k=v] [--only-open] [--hours 168] [--limit 20] [--sort deadline|created] [--json]
128
+ ente activity create --type meeting --title "Call with Jane" --entity "Jane Doe" --entity "Acme Corp" --space "Work" [--content "…"] [--content-file ./notes.md] [--auto-link --entity-space-grant-fingerprint <token>] [--json]
129
+ ente activity search "quarterly review" [--entity "Acme"] [--type meeting] [--limit 10] [--json]
130
+ ente activity get <activityId> [--json] # complete detail: body, full nested agenda, messages/replies, entities, attachments
131
+ ente activity update <activityId> [--title "…"] [--content "…"] [--entity-add "Bob"] [--entity-remove "Carol"] [--json]
132
+ ente activity content read <activityId> [--cursor <cursor> --expected-version <version>] [--max-blocks 20] [--max-characters 12000] [--json]
133
+ ente activity content edit <activityId> --expected-version <version> --operations-file ./operations.json [--json]
134
+ ente activity message add <activityId> (--content "…" | --content-file ./update.md) [--json]
135
+ ente activity attachment upload <activityId> ./file.pdf [--name "Contract.pdf"] [--json]
136
+ ente activity delete <activityId> [--json]
137
+ ente activity restore <activityId> [--json]
138
+
139
+ # Meeting agendas
140
+ ente agenda create-point --meeting <meetingActivityId> --title "Decisions" [--content="…"] [--content-file ./decisions.md] [--parent <agendaPointId>] [--after <agendaPointId>] [--json]
141
+ ente agenda link-task --point <agendaPointId> --task <activityId|#N> [--json]
142
+
143
+ # Excalidraw Canvas HTML prototypes
144
+ ente canvas boards <entityId> [--json]
145
+ ente canvas html list <boardId> [--json]
146
+ ente canvas html get <boardId> <elementId> [--json]
147
+ ente canvas html create <boardId> --title "Prototype" --file <html-path|-> [--placement below_content|empty_region|manual] [--direction right|down|left|up] [--x N --y N] [--width N --height N] [--operation-id <stable-key>] [--json]
148
+ ente canvas html update <boardId> <elementId> --file <html-path|-> [--title "Revised"] [--x N --y N] [--width N --height N] [--json]
149
+ ente canvas html delete <boardId> <elementId> [--json]
150
+
151
+ # Tasks (activities with type=task; short-ids #N, deadlines, assignees)
152
+ ente tasks [--json] # open tasks by deadline
153
+ ente task list [--due today|overdue|all] [--entity "Jane"] [--json]
154
+ ente task get 5 [--space "Work"] [--json]
155
+ ente task create "Reply to Jane" --entity "Jane Doe" --space "Personal" [--deadline "2026-05-23 14:00"] [--content "…"] [--assignee <userId-or-email>] [--json]
156
+ ente task update 5 [--title "…"] [--content "…"] [--deadline "2026-05-26"] [--attr k=v] [--json]
157
+ ente task done 5 [--json]
158
+ ente space members --space "Work" [--json]
159
+ ente task assign 5 <userId-or-email> [--json]
160
+ ente task unassign 5 <userId-or-email> [--json]
161
+ ente task set-assignees 5 --assignee <userId-or-email> [--json]
162
+ ente notification send --subject "Weekly brief" --text "Your brief is ready." [--html-file ./brief.html] [--attachment ./handoff.md] [--image ./attachment.png] [--inline-image chart=./chart.png] [--json]
163
+ ente task clear-assignees 5 [--json]
164
+
165
+ # Bound Ente agent (operator key)
166
+ ente agent config show [--json]
167
+ ente agent threads [--include-archived] [--limit 20] [--json]
168
+ ente agent threads [--attention user|agent|none] [--json]
169
+ ente agent show <ente-thread-id> [--json]
170
+ ente agent new "Question" [--title "Title"] [--request none|ack|text] [--request-prompt "Prompt"] [--html-file ./message.html] [--idempotency-key <stable-key>] [--json]
171
+ ente agent send <ente-thread-id> "Reply" [--request none|ack|text] [--request-prompt "Prompt"] [--html-file ./message.html] [--idempotency-key <stable-key>] [--json]
172
+ ente agent config set-prompt (--text "New prompt" | --file ./prompt.md) [--json]
173
+ ente agent schedules configure --file ./schedules.json [--json]
174
+
175
+ # Agent inbox (available when the bound agent has an active inbox)
176
+ # The owner must first add each exact correspondent in Ente inbox settings.
177
+ # Unlisted inbound mail is owner-only and is absent from CLI reads. Sends and
178
+ # replies fail unless the final recipient is allowlisted (or an admin-granted
179
+ # unlimited account enabled send-to-anyone for this mailbox).
180
+ ente agent mail address [--profile <name>] [--json]
181
+ ente agent mail threads [--profile <name>] [--unread] [--needs-reply] [--limit 20] [--cursor <cursor>] [--json]
182
+ ente agent mail show <thread-id> [--cursor <cursor>] [--json]
183
+ ente agent mail send --to person@example.net --subject "Update" --text "Plain fallback" [--html "<p>Rich update</p>" | --html-file ./message.html] [--attachment ./reference.pdf] [--idempotency-key <stable-key>] [--json]
184
+ ente agent mail reply <thread-id> --message <message-id> (--text "Reply" | --text-file ./reply.txt) [--html "<p>Reply</p>" | --html-file ./reply.html] [--attachment ./handoff.docx] [--idempotency-key <stable-key>] [--json]
185
+ ente agent mail mark <thread-id> --state-version <version> (--handled | --open | --needs-reply | --read | --unread) [--json]
186
+ ```
187
+
188
+ Agent operator credentials are bound server-side to one exact agent. Agent read
189
+ adds `agent:read` and, while the inbox is active, `mail:read`. Agent write adds
190
+ `agent:write`, `agent:communicate`, and, while the inbox is active, `mail:send`.
191
+ Use `agent threads --attention agent`, then `agent send`; the CLI claims the current
192
+ attention version before replying so concurrent cron workers cannot duplicate work.
193
+ The prompt and
194
+ scheduled runs are Ente configuration for the Ente agent counterpart. They are
195
+ not work instructions or scheduler settings for the external operator. The key
196
+ cannot select a different agent, mailbox, or sender. All authenticated commands
197
+ accept optional `--profile <name>`; use `ENTE_PROFILE` only when a launcher must
198
+ select one of several stored credentials.
199
+ Send and reply support repeatable `--inline-image CONTENT_ID=PATH` alongside
200
+ `--attachment PATH`. Supply HTML containing `<img src="cid:readiness">` and
201
+ `--inline-image readiness=./readiness.png`. The CLI embeds local file bytes in
202
+ the email; use CID images for private charts, never remote URLs or data URIs.
203
+ Inline images must be PNG, JPEG, GIF, or WebP (verified by file signature).
204
+ Content-IDs must be unique, case-sensitive, at most 128 characters, start with a
205
+ letter or number, and contain only letters, numbers, `.`, `_`, `@`, or `-`.
206
+ Every inline image must have a matching HTML CID reference, and every CID
207
+ reference must have an image. Keep the complete report in the required plain-text
208
+ fallback; HTML and images do not replace it.
209
+
210
+ The combined limit is **four files** across ordinary attachments and inline
211
+ images, **750,000 bytes per file** (3,000,000 decoded bytes total). Four Health
212
+ charts fit only when no ordinary attachment is also sent. Five SaaS Spending
213
+ charts exceed this limit and are rejected; inline images do not bypass it.
214
+ For example:
215
+
216
+ ```bash
217
+ ente agent mail send --to owner@example.net --subject "Readiness" --text-file ./report.txt --html-file ./report.html --inline-image readiness=./readiness.png --idempotency-key readiness-report-v1
218
+ ente agent mail reply <thread-id> --message <message-id> --text-file ./report.txt --html-file ./report.html --inline-image readiness=./readiness.png --attachment ./notes.txt --idempotency-key readiness-reply-v1
219
+ ```
220
+
221
+ Retries must keep filenames, MIME types, Content-IDs, file order, and exact file
222
+ bytes unchanged, along with the recipient, text, HTML, and reply target. A changed
223
+ image or CID with the same key is rejected. Reported `sent` means transport
224
+ accepted the message; delivery feedback may later report delivered, delayed,
225
+ bounced, or complained. An unknown delivery outcome must never be retried with a
226
+ new key.
227
+
228
+ `--text` and `--html` accept inline strings; use the
229
+ corresponding `--*-file` option for UTF-8 files. If a send or reply returns an
230
+ ambiguous timeout, retry the exact operation with the same
231
+ `--idempotency-key`. Use a new key whenever any payload field changes.
232
+
233
+ For a focused update to an existing long body, use `activity content read`, select the returned
234
+ version-scoped block targets, then call `activity content edit` with the exact `contentVersion`.
235
+ The operations file is either a JSON array or `{ "operations": [...] }`; supported operation types
236
+ are `replaceBlock`, `insertBefore`, `insertAfter`, `deleteBlock`, `replaceText`, and `append`.
237
+ Use `replaceText` with a unique exact Markdown substring for file-patch-like changes inside a large
238
+ block. Partial Markdown edits preserve existing rich blocks but do not create interactive HTML
239
+ blocks; use the dedicated HTML block commands for those. If the version conflicts, reread and
240
+ reconsider the edit; never overwrite newer content.
241
+ Keep `activity update --content-file` for deliberate whole-document imports or rewrites, and use
242
+ `activity message add` for chronological progress that belongs outside the main body.
243
+
244
+ For a Canvas prototype, resolve the entity ID, call `canvas boards`, and insert the source with a
245
+ stable `--operation-id`. Prefer `below_content` for a predictable append or `empty_region` when the
246
+ board is already dense. The create result includes `reviewPath`. Update and delete perform a fresh
247
+ read and fail on a concurrent human edit. These remote scene changes sync into open boards, but do
248
+ not enter another browser's local undo stack.
249
+
250
+ ### Recording (voice) pipeline
251
+
252
+ ```bash
253
+ ente recording-pipeline show [--json] # prompt + dictionary
254
+ ente recording-pipeline set-prompt "<text>" | --file <path|-> | --edit
255
+ ente recording-pipeline reset-prompt # clear → starter regenerated next run
256
+ ente recording-pipeline set-dictionary "<text>" | --file <path|-> | --edit
257
+ ```
258
+
259
+ - Edits **your own** user's voice-pipeline settings (same functions as web Settings → Voice pipeline).
260
+ - `set-prompt`/`set-dictionary` are full replacements; exactly one source (`<value>` | `--file` | `--edit`).
261
+
262
+ ### Own models (own-models plan only)
263
+
264
+ Users on the hidden €0 own-models plan bring OpenAI-compatible endpoints (e.g. LiteLLM). Ente then sends their content only to those endpoints; a feature stays disabled until its slot has a model.
265
+
266
+ ```bash
267
+ ente models status # slots, connections, web search
268
+ printf %s "$KEY" | ente models connection add LiteLLM --base-url https://llm.example.eu/v1 --api-key-stdin
269
+ ente models set agent LiteLLM claude-sonnet # slots: agent ask recording transcription summary small
270
+ ente models test [slot] # real request; agent/ask/recording must call a tool
271
+ ente models web-search on|off # Linkup web search for the agent (default off)
272
+ ente users set-plan <email> own_models # admin: move a user onto the plan
273
+ ```
274
+
275
+ ### Recordings (admin — debug a failing recording)
276
+
277
+ ```bash
278
+ ente recording list [--user <email|id>] [--status error] [--limit 20] [--json]
279
+ ente recording show <recordingId> [--json] # status, error, transcript size, activity count
280
+ ente recording inspect <recordingId> [--json] # audio container: brands, fragmented?, box counts
281
+ ente recording rerun <recordingId> [--wait] [--timeout 900] [--json]
282
+ ```
283
+
284
+ - Admin-only (`api.admin.recordings.*`); the ordinary `recordings.*` API is creator-scoped.
285
+ - `rerun` never modifies or deletes the stored audio; `--wait` polls to `done`/`error` and exits non-zero on failure.
286
+ - `--status` scans newest-first and says so when the sweep is capped.
287
+
288
+ ### Feedback board
289
+
290
+ ```bash
291
+ ente feedback send "<summary>" [--category missing|confusing|wrong_data|workflow|bug|other] \
292
+ [--situation "…"] [--goal "…"] [--need-to-see "…"] [--need-to-do "…"] [--reason "…"] [--workaround "…"]
293
+ ente feedback list [--status offen|todo|bearbeitung|klaerung|abgeschlossen|spaeter] [--text "…"] [--limit 50] [--json]
294
+ ente feedback view <feedbackId> [--json] # full item + comment thread
295
+ ente feedback comment <feedbackId> "<body>" # reply on the thread
296
+ ente feedback status <feedbackId> <status> # move to a board column
297
+ ```
298
+
299
+ - Same in-app feedback board as the web composer (`convex/feedback.ts` public functions) — no GitHub issue.
300
+ - Every authenticated user may submit and manage the shared board. Screenshots/attachments are web-composer only.
301
+
302
+ ### Deadline formats
303
+
304
+ | Input | Interpretation |
305
+ |---|---|
306
+ | `tomorrow` / `tomorrow 14:00` | Tomorrow 22:00 / 14:00 Berlin |
307
+ | `today` / `today 14:00` | Today 22:00 / 14:00 Berlin |
308
+ | `+3 days` / `+1 week` | Relative, 22:00 Berlin |
309
+ | `2026-03-15` / `2026-03-15 14:00` | That date (22:00 default) Berlin |
310
+ | `2026-03-15T14:00:00+01:00` | ISO 8601 with offset |
311
+
312
+ ---
313
+
314
+ ## Limits & boundaries
315
+
316
+ - **Rename is supported**: `ente entity rename "<old>" "<new>"` (or `entity update <id> --name`).
317
+ - **Relationships are spaceless**, but access propagates upward through the active graph. Every active parent and ancestor must belong to every active child space. A failed write returns the exact grant preview and `grantFingerprint`; retry with `--share-parents --parent-space-grant-fingerprint <token>` so concurrent graph changes cannot expand the approved grant set.
318
+ - **Activity ownership stays inside its space.** An entity cannot leave a space while it owns activities there. Use `--remove-from-activities` to remove all affected ownership links when every activity has another owner.
319
+ - **Cross-space linking is bounded**: an activity can only link entities already in its target space. A failed write returns the exact entity-space grant fingerprint. Retry with `--auto-link --entity-space-grant-fingerprint <token>` only after confirming that exact grant set; concurrent hierarchy changes fail closed.
320
+ - **Merging duplicates and adding an entity to a shared space are web-UI only** — there is no API endpoint. Run `ente guide limits` for the full rundown.
321
+
322
+ ---
323
+
324
+ ## Workflow pattern
325
+
326
+ 1. **Check auth** — `ente auth status` before data commands.
327
+ 2. **Search first** — `ente search "name" --json` before creating entities (avoid duplicates).
328
+ 3. **Identify entities** — find the most specific existing owners; inspect direct children when a broad project or organization matches.
329
+ 4. **Determine space** — personal for private notes, shared for team-visible activities.
330
+ 5. **Operate** — entity/activity/task CRUD (prefer `--json` for parsing).
331
+ 6. **Link precisely** — link independently central entities, prefer specific children, and omit ancestors that are implied by hierarchy.
332
+ 7. **Confirm** — re-run the relevant list/get after writes to verify.
333
+
334
+ ---
335
+
336
+ ## Error handling
337
+
338
+ - **"Not authenticated"**: run `ente auth login`.
339
+ - **"Ambiguous match"**: multiple entities match — use the full Convex ID.
340
+ - **"No entity found"**: check spelling, try `ente search`.
341
+ - **"not in '<space>'" (cross-space)**: confirm the listed grants, then retry with `--auto-link --entity-space-grant-fingerprint <token>`, or add the entity to that space in the web UI.
342
+ - **"Cannot remove all entities"**: an activity must keep at least one entity.
343
+
344
+ Parent relationships are spaceless. Both entities must be accessible. Every active parent and ancestor must belong to every active child space. Commands that would expand parent access fail with a grant preview and fingerprint. Retry with both confirmation flags. A parent cannot be removed from a space while an active child remains there.