ente-cli (0.4.62)

Published 2026-10-18 21:19:02 +00:00 by ivo.zilkenat

Installation

registry=https://gitea.i.ivo-zilkenat.de/api/packages/ivo.zilkenat/npm/
npm install ente-cli@0.4.62
"ente-cli": "0.4.62"

About this package

CLI for ente — relationship manager and knowledge graph (Convex backend).

ente CLI

Command-line interface for ente — a relationship manager and knowledge graph (people, orgs, projects, topics, places, objects 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. Every external credential is bound to an Ente agent. With read, it can read allowed space content and inspect the bound agent. It can also mark inbox threads read/unread, and change their workflow state when an inbox is enabled. write additionally permits changes within the agent’s current space policy, agent configuration changes, and sending email from its active permitted inbox. The CLI saves approved profiles before activating their keys, so a failed local save cannot leave active keys behind.

For headless integrations, create or select an agent in /agents, issue a credential from its Connections settings, and enter it directly in the terminal. Several credentials may belong to one agent. Existing migrated keys remain valid:

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

Agent keys use scoped REST calls and signed CLI JWTs carrying the agent and credential IDs. Content calls recheck the live key and agent policy, including cached JWT calls. Human-only settings and administration stay in the web app; there is no unrestricted account-key fallback. CLI pairing without --agent creates a named connection agent. MCP authorization creates a connection agent named for the client.

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 --cc owner@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. ente agent list shows the agent bound to this credential, including migrated connection keys. Migrated keys keep their original scopes: listing that identity does not grant prompt or conversation access. History needs agent:read; agent new and agent send need agent:communicate and post messages as the agent. They do not invoke a hosted model or impersonate a human user. 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 --cc owner@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> --reply-all --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 accept repeatable --cc ADDRESS, up to 24 CC addresses and 25 recipients total. Ente normalizes and deduplicates addresses and checks every recipient against the owner's sending policy. Add a person only when the owner has authorized that conversation and its content for them.

Replies default to the exact inbound sender. --reply-all resumes recipients from prior outbound mail in the same thread; it never copies inbound To, CC, or Bcc headers. On a new inbound thread, use explicit --cc to add an authorized person. All resumed recipients are checked again, so a removed sending grant blocks the reply. Keep CC and reply-all choices unchanged when retrying an ambiguous send with the same idempotency key.

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> --reply-all --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

Existing provider drafts retain their attachments when edited or sent through user-mailbox, including the web composer's 25 MB combined raw-file budget (25,000,000 bytes, at most 24 files). The complete MIME message must fit 35 MiB; providers can allow less. loadDraft returns file metadata and a reviewed draft version, without file bytes or private storage references. Attach new files in the web composer. The agent's own inbox keeps its separate attachment limits.

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.

Guardian health (global admin)

ente health page --profile default --source toolMessages --since <epoch-ms> --until <epoch-ms> --json reads one content-free aggregate page. Use --source threads --status idle|running|error or --source recordings --status pending|transcribing|structuring|reflecting|done|error for current job counts. Use --since 0 for active jobs; terminal recording statuses require a positive --since and a window of at most seven days. Legacy terminal rows without update timestamps are outside that coverage. --stale-after-ms defaults to 1800000; --limit accepts 1–100. Follow data.continueCursor with --cursor and unchanged arguments until data.isDone. Counts are page-local. Tool windows are at most seven days. This is a human-only global administration endpoint. Agent-bound CLI credentials cannot call it, including credentials sponsored by an administrator. Use the web administration interface for these operations; creating a broader agent key does not grant access. No customer content or record IDs are returned. Unknown tool names become other. See docs/admin-health-monitoring.md for collector continuity and limits.

Assigned tasks and replies

Assigned agent work is available through ente agent tasks <operation>. Start with ente agent tasks list --view attention --json, inspect each assignment, read its discussion, optionally reply with a stable idempotency key, and acknowledge only the returned version you processed. Newer replies remain pending. The shipped skill documents pagination, long-message chunks and optional five-minute claims. Your prompt and schedule control the workflow.

Task assignment accepts multiple agents alongside humans. Use repeatable ente activity create --type task --agent-assignee <agentId> with the usual entity, space and title arguments, or ente activity update <activityId> --agent-assignee <agentId>. Updating replaces agent assignees and preserves human assignees. Use --clear-agent-assignees to remove them. Only active agents with write access qualify.

Scheduled runs also accept runCondition: "new_chats": skip model execution unless this agent has new manual or recording chats since its previous scheduled check. Scheduled/reflection chats do not trigger it; explicit Run now bypasses the condition.

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
Details
npm
2026-10-18 21:19:02 +00:00
2
447 KiB
Assets (1)
Versions (78) View all
0.4.77 2026-10-24
0.4.76 2026-10-23
0.4.75 2026-10-23
0.4.74 2026-10-23
0.4.73 2026-10-22