ente-cli (0.4.58)
Installation
registry=https://gitea.i.ivo-zilkenat.de/api/packages/ivo.zilkenat/npm/npm install ente-cli@0.4.58"ente-cli": "0.4.58"About this package
ente CLI
Command-line interface for ente — a relationship manager and knowledge graph (people, orgs, projects, topics and the notes/calls/tasks/conversations logged against them).
TypeScript, built on clipanion, bundled with esbuild
into a single self-contained file, published to npm and Ivo's Gitea npm registry. It talks
to ente's external REST API (/api/external/*) with a static Bearer API key.
Install
npm i -g ente-cli
# Ivo's registry remains available with the same package and version:
npm i -g ente-cli --registry https://gitea.i.ivo-zilkenat.de/api/packages/ivo.zilkenat/npm
Setup
Connect a normal CLI profile with browser approval. Replace the site URL and email with your Ente deployment and account:
ente auth pair --url https://your-deployment.convex.site --email you@example.com
The CLI prints a review link and six-digit code. Open the link, sign in, inspect the requested profile, enter the code, and approve it. The CLI generates its key locally and sends its hash and short prefix to Ente. The full key stays local and never appears in the browser or terminal output. Keep the CLI running until it verifies the new profile.
To connect an operator to one agent, use that agent's ID from ente agent list
and name the local profile:
ente auth pair --url https://your-deployment.convex.site --email you@example.com \
--profile mail-operator --agent <agent-id> --access write
For up to ten operators, put the exact agent IDs and local profile names in a JSON file outside a repository:
[
{ "profile": "operator-a", "agentId": "<agent-id-a>", "access": "write" },
{ "profile": "operator-b", "agentId": "<agent-id-b>", "access": "read" }
]
ente auth pair --url https://your-deployment.convex.site --email you@example.com \
--manifest /private/path/operators.json
One Ente approval page lists all profiles and scopes. Existing local profiles
are never overwritten unless --replace is supplied. A stopped or expired CLI
run must be started again. Pending requests expire after ten minutes.
Both agent access modes can read and change Ente data and manage spaces.
With read, the key can inspect the bound agent and inbox, mark inbox threads
read/unread, and change their workflow state. write also permits agent
changes and sending email. The CLI saves approved profiles before
activating their keys, so a failed local save cannot leave active keys behind.
For headless integrations or a legacy key, generate an API key in the web app and enter it directly in the terminal:
ente auth login --url https://your-deployment.convex.site --key-stdin
Credentials are stored at ~/.config/ente/config.toml (~/Library/Application Support/ente/config.toml on macOS), 0600. ENTE_API_URL and ENTE_API_KEY
override the file only when both are set.
An agent operator profile is bound to that agent's configuration, threads, scheduled runs, and inbox when enabled:
ENTE_PROFILE=mail-operator ente agent config show
ENTE_PROFILE=mail-operator ente agent mail threads --unread
Operator keys use the CLI's scoped REST commands. They cannot be exchanged for the legacy full-account CLI session token, so the bound-agent restriction cannot be bypassed through direct Convex commands. Use a normal account key for legacy administrative CLI commands that require that session token.
Named profiles are optional. Use one only when a person or process deliberately
switches between several credentials. --profile overrides ENTE_PROFILE.
Profiles do not activate from the current directory and are not a security
boundary. Use a separate OS account or container when operators on the same
machine must not read each other's keys. Never commit a key or put it in a
project .env file.
Usage
ente search "Alice"
ente entity list --type person
ente entity rename "Lorey Georg" "Georg Lorey"
ente task list --due today
ente activity create --type note --title "Meeting notes" --entity "Alice" --space "Personal"
ente activity get <activityId> --json # includes the body, nested agenda, messages/replies, entities, and attachments
ente agenda create-point --meeting <meetingActivityId> --title "Decisions" --content="- Ship the smaller scope"
ente agenda link-task --point <agendaPointId> --task "#12"
ente activity message add <activityId> --content "Decision: ship the smaller scope first."
ente activity content read <activityId> --json
ente activity content edit <activityId> --expected-version 42 --operations-file edits.json --json
ente canvas boards <entityId>
ente canvas html create <boardId> --title "Prototype" --file ./prototype.html --operation-id prototype-v1
ente notification send --subject "Weekly brief" --text "Your brief is ready." --html-file ./brief.html --attachment ./brief.pdf --inline-image chart=./chart.png
ente agent config show
ente agent threads
ente agent mail threads --unread
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
ente tasks
ente guide # concepts; `ente guide <topic>`: entities, tasks, activities, search, patterns, limits
Every command supports --json. Run ente --help or ente <group> --help.
Command groups
| Group | Commands |
|---|---|
auth |
pair, login, status, logout, profiles |
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) |
activity |
list, create, search, get, update, delete, restore, message add, attachment upload |
agenda |
create-point, link-task |
task |
list, get, create, update, done, assign, unassign, set-assignees, clear-assignees |
pins |
list |
space |
members |
recording |
list, show, inspect, rerun (admin only) |
canvas |
boards, html list, html get, html create, html update, html delete |
notification |
send (emails only your own Ente account address; optional HTML, file attachments, and CID inline images) |
agent |
list, threads, show, new, send, config show, config set-prompt, schedules configure |
agent mail |
address, threads, show, send, reply, mark |
| top-level | search, ask, query, tasks, guide |
Agent operators and inboxes
An agent operator key can read and change Ente data, manage spaces, and access
one bound agent. Agent read includes Ente configuration such as the prompt,
Ente thread history, scheduled-run configuration, inbox reads, and thread status
updates when an inbox is active. Agent
write additionally allows prompt changes, full scheduled-run replacement, and
inbox send/reply. New write-capable keys also receive agent:communicate, which
lets the bound external agent start, claim, and reply to external threads without
calling an Ente-hosted model. Ente prompt and scheduled runs configure the Ente agent
counterpart; they are not instructions or schedules for the external operator.
The caller cannot select another agent, mailbox, or sender.
The corresponding scopes are agent:read, agent:write, mail:read, and
mail:send, and agent:communicate.
The inbox owner must add each exact correspondent in Ente. Unlisted inbound mail stays owner-only and never appears in operator REST, MCP, WebMCP, or CLI reads. New sends and replies are rejected before persistence unless the final recipient is allowed. An administrator-granted unlimited-mail account may enable send-to-anyone or receive-from-anyone separately for each mailbox.
ente agent config show
ente agent threads --include-archived --limit 20
ente agent show <ente-thread-id>
ente agent new "Can I publish this?" --title "Release note" --request text --idempotency-key release-question-1
ente agent threads --attention agent
ente agent send <ente-thread-id> "Published." --request ack --request-prompt "Release note published" --idempotency-key release-answer-1
ente agent config set-prompt --text "Review finance updates."
ente agent config set-prompt --file ./ente-agent-prompt.md
ente agent schedules configure --file ./schedules.json
ente agent mail address
ente agent mail threads --unread --limit 20
ente agent mail show <thread-id>
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
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
ente agent mail mark <thread-id> --state-version 4 --handled
schedules.json is the complete replacement list. Omitted schedules are
deleted:
[
{
"enabled": true,
"prompt": "Review new finance mail and prepare follow-ups.",
"timeMinutes": 480,
"timezone": "Europe/Berlin"
}
]
Send and reply support repeatable --inline-image CONTENT_ID=PATH alongside
--attachment PATH. Supply HTML containing <img src="cid:readiness"> and
--inline-image readiness=./readiness.png. The CLI embeds local file bytes in
the email; use CID images for private charts, never remote URLs or data URIs.
Inline images must be PNG, JPEG, GIF, or WebP (verified by file signature).
Content-IDs must be unique, case-sensitive, at most 128 characters, start with a
letter or number, and contain only letters, numbers, ., _, @, or -.
Every inline image must have a matching HTML CID reference, and every CID
reference must have an image. Keep the complete report in the required plain-text
fallback; HTML and images do not replace it.
The combined limit is 24 files across ordinary attachments and inline images, 750,000 bytes per file, and 3,000,000 decoded bytes total. For 24 images, the average image must be at most 125,000 bytes, with less room when ordinary attachments are also included. Inline images share the byte budget. For example:
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
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
Retries must keep filenames, MIME types, Content-IDs, file order, and exact file
bytes unchanged, along with the recipient, text, HTML, and reply target. A changed
image or CID with the same key is rejected. Reported sent means transport
accepted the message; delivery feedback may later report delivered, delayed,
bounced, or complained. An unknown delivery outcome must never be retried with a
new key.
--text and --html accept inline strings. Their --text-file and
--html-file counterparts read UTF-8 files. After an ambiguous timeout, retry
the exact same operation with the same --idempotency-key; changing the body,
recipient, thread, or message requires a new key.
Operational recipes (playbooks)
Copy-pasteable, task-oriented recipes live in playbooks/ — log a
meeting, rename/merge an entity, work around cross-space linking, etc. Start there
for "how do I do X".
Develop in-repo / build
pnpm setup:cli # from the repository root; once per checkout
cd cli
pnpm dev entity list # run from source via tsx
pnpm typecheck # the build-from-truth gate (tsc --noEmit)
pnpm build # → dist/cli.mjs (+ dist/SKILL.md)
The CLI is not a workspace member. pnpm setup:cli installs its locked
dependencies separately. The repository's pnpm check typechecks and tests the
CLI without installing dependencies.
Publishing is automatic: a push to main touching cli/** or the publish
workflow selects a version above both registries, tests and packs once, then
publishes identical bytes to npm and Gitea. npm uses GitHub OIDC; Gitea keeps
the existing package token. See .github/workflows/publish-cli.yml and
docs/cli-architecture.md for setup and retry instructions.
Architecture
core/ brand-neutral: transport (REST/fetch), config, output, errors, update, command base.
ente/ branded: the /api/external client, types, resolve, deadline, formatters, commands/*.
cli.ts clipanion bootstrap: registers every command group.
The dependency direction is one-way — ente/ imports core/, never the reverse.
See CLAUDE.md for the layering rules and conventions.
Public installation and recovery guide
This is the Ente private knowledge-graph / relationship-manager CLI at ente.fast,
not Ente Photos. Follow https://ente.fast/cli.md for new installations, upgrades,
PATH conflicts, configuration reuse, legacy API keys, and stale authentication.
Keep working credentials. ente auth status --json reports local configuration
without key material; verify server access with ente entity list --limit 1 --json.
Use auth login --key-stdin for hidden local key entry as shown in the guide.
Never put secrets in chat, repositories, project .env files, or logs.
Process a permitted user mailbox
A user's Gmail/IMAP inbox is separate from the agent's own email address. In
Ente /agents, the owner selects the mailboxes this personal agent can read,
classification/reply permissions, destination spaces, and full conversation
publication consent. Processing is optional; use the classifier and reply
schedule templates. Schedules support intervalHours: 1 | 24 and
mailPurpose: "classification" | "replies" to skip empty queues before AI runs.
ente agent user-mailbox --request '{"operation":"list","purpose":"classification","limit":20}'
ente agent user-mailbox --request-file ./mail-operation.json
Use the returned threadId to read or claim. External claims require the
agentThreadId of an owned agent conversation; native tools bind it automatically.
After claiming, call classify with the token and decision: "include" | "skip".
Include requires spaceId. Entity owners are optional: omit entityIds or pass []; any supplied owners must already be accessible in that space.
Reply jobs claim purpose: "replies", read project/person context, then suggest
with the token, contextVersion from read, and one to three short suggestions.
Read permission can include provider-saved drafts. Sending or changing inbox
state requires the separate full mailbox grant. Send uses a loaded draft's exact
version; an external operation also needs an active owned agent conversation.
Lists default to 20 and allow at most 50 rows. List/read responses are bounded to
16 KiB. Follow every returned cursor, including older backlog. Read text is
newest first and versioned; hasMoreText indicates continuation. Claims expire
in five minutes. New mail, manual corrections, permission changes, or expired
claims require a fresh claim. Default budgets are 20 changes per agent execution
and 100 per UTC day. A successful operation acknowledges only its own purpose.
Published conversations remain durable after provider cache expiry/disconnect.
Their individual messages appear in entity activity feeds; activity content reads
return bounded, read-only email blocks with continuation cursors.
Dependencies
Development Dependencies
| ID | Version |
|---|---|
| @types/node | ^22.10.0 |
| clipanion | 4.0.0-rc.4 |
| convex | ^1.46.0 |
| esbuild | 0.27.0 |
| smol-toml | ^1.7.1 |
| tsx | ^4.21.0 |
| typescript | ^6.0.3 |