@skyporch/daykeeper-cli
v0.5.0
Published
Machine-readable command line for the Daykeeper management API
Readme
Daykeeper CLI
For more about Daykeeper, visit mydaykeeper.com.
A command line for people, agents, and CI jobs managing Daykeeper. It calls the
@skyporch/[email protected] SDK and returns one versioned JSON envelope
per invocation. The code is Apache-2.0; see LICENSE and
RELEASING.md.
Get a support inbox with one command
npx @skyporch/daykeeper-cli init --name "Acme Support"That's it. No sign-up, card, website, or DNS. init enrolls a machine owner,
creates a Free workspace with one API inbox, waits for it to be ready, turns it
on, and stores the credential under ~/.config/daykeeper (directory mode
0700, file mode 0600). It prints the workspace and inbox IDs, the next steps,
and ready-to-paste SDK and MCP configuration. Run it again and it picks up where
it stopped; it never creates a second workspace, credential, or inbox.
Run in a terminal, init prints readable text. Add --json, or capture stdout
from an agent or script, for the JSON envelope.
Every other command then uses the stored credential, with nothing to export:
npx @skyporch/daykeeper-cli tenants listEvery init ends with a way for a person to own the inbox. Until somebody
claims it, customer messages reach only the agent and nobody is emailed about
them, so the output leads with a handoff message to relay as is:
- By default, an open claim link: whoever opens it first and signs in at https://app.mydaykeeper.com owns the workspace.
- With
--owner-email, a claim only that address can accept (and that the person also finds waiting when they sign in with it). Prefer it whenever you know the address. - With
--connect,initprints the link (on stderr), opens it in the browser when a person is at the terminal, and waits up to 3 minutes for them to accept it, then reports who owns the inbox. - With
--no-claim, no claim is issued (for CI, or a workspace a person already owns).
npx @skyporch/daykeeper-cli init --name "Acme Support" --owner-email [email protected]
npx @skyporch/daykeeper-cli init --name "Acme Support" --connect
npx @skyporch/daykeeper-cli claim # the open link again, or a new one
npx @skyporch/daykeeper-cli claim --email [email protected]The link carries its token in the URL fragment and is printed unredacted,
because it is the handoff: treat it like a password reset link, and use
--no-claim for runs whose output is shared (CI logs, public transcripts). It
works once and expires in 72 hours. The state file keeps a pending claim's link
beside the machine credential (which can mint a new claim anyway), so rerunning
init prints the same link, or who claimed it, or a fresh link once the old
one expired. claim --reissue revokes the pending link and issues a new one,
and claim status lists what the server holds.
Install it globally to type daykeeper instead of npx @skyporch/daykeeper-cli:
npm install --global @skyporch/daykeeper-cli
daykeeper tenants listThe credential is redacted from output unless you pass --reveal-key, but
<home>/mcp.json always carries the literal credential so an MCP client can
read it. Full flags, state layout, resume behavior, and error codes are in
COMMANDS.md.
Authenticate
Each command uses the first credential it finds:
--token-stdin, with the token piped from a trusted credential provider.DAYKEEPER_API_KEY, injected by your secret manager or CI environment.DAYKEEPER_ACCESS_TOKENstill works as a deprecated alias.- The credential
initstored in<home>/credentials.json.
Set at most one of the first two. A supplied credential goes to --base-url,
then DAYKEEPER_API_URL. Without either, the key init stored goes to the
origin that issued it; any other key goes to https://api.mydaykeeper.com
unless this machine's state is for a different origin, in which case set the URL
explicitly. Include any
reverse-proxy prefix in the URL. Remote origins must use HTTPS;
http://127.0.0.1 and http://localhost are supported for local development.
URLs with credentials, query strings, or fragments are rejected, and requests
never follow redirects.
The stored credential is only ever sent to the origin that issued it. If you ran
init with --origin or DAYKEEPER_ORIGIN, set the same origin for later
commands; a different one fails with STATE_ORIGIN_MISMATCH before any request.
Use --home or DAYKEEPER_HOME to point at a state file outside the default
location. A stored credential near expiry is rotated before it is used.
init and claim always run under the stored credential. They refuse
--token-stdin, and a supplied DAYKEEPER_API_KEY that is not the stored one.
# DAYKEEPER_API_KEY is supplied by your environment.
daykeeper capabilities
# A credential provider can pipe the token instead.
credential-provider print-daykeeper-api-key | daykeeper capabilities --token-stdinThe credential provider above represents your existing secret-management command, not a bundled Daykeeper command. Tenant IDs select resources; they do not grant access or change the token's organization. The API remains responsible for verifying credentials, scopes, and tenant membership. Tokens must be 20–16,384 bearer characters. The CLI accepts no token argument and never opens an interactive sign-in prompt.
Run from this repository
Use Node.js 20 or newer and pnpm 10.8.0:
pnpm install --frozen-lockfile
pnpm build
node dist/cli.js --helppnpm daykeeper --help runs the same CLI from source.
Plan, inspect, then apply
daykeeper tenants plan --input tenant.json > tenant-plan.json
# Inspect the returned changes, warnings, requiredScopes, version, and expiry.
jq '.data' tenant-plan.json
# Apply only when approved, using the exact plan and a durable key for this action.
daykeeper tenants apply \
--plan-id 33333333-3333-4333-8333-333333333333 \
--plan-version 1 \
--idempotency-key daykeeper-acme-tenant-create-0001tenants plan and email-channels plan create expiring server-side plans but do
not create provider resources. Apply is a separate explicit command. The CLI
does not generate plan IDs, fetch replacement plans, change versions, generate
idempotency keys, or automatically repeat mutations.
Use --input - to read a JSON body from stdin. JSON must match the command's
strict schema and stay within 512 KiB. Unknown fields—including organization,
role, or policy overrides—are rejected. When using --token-stdin, JSON must
come from a regular file; one stdin stream cannot carry both token and body.
The command names, exact flags, scope requirements, flow examples, and output
schema are documented in COMMANDS.md. --help provides the
command catalog as JSON without making a request.
Errors, cancellation, and safe retries
Every result is one JSON line on stdout. The one exception is init run in a
terminal without --json, which prints readable text. There are no prompts or
progress messages.
Exit status is 0 for success and 1 for a command error. The executable uses
130 for SIGINT and 143 for SIGTERM after emitting a cancellation error.
Use --timeout-ms or DAYKEEPER_TIMEOUT_MS to set one 1–60 second budget for
input reading and the API request (default: 30 seconds). Cancellation aborts the
local request, not work already accepted by the server. An interrupted mutation
reports mutationOutcome: "unknown"; inspect the relevant resource or operation
before retrying. For plan/apply and flow mutations, reuse the original idempotency
key for the exact same logical action. Operation retries have no idempotency key
in SDK 0.2.0; they are never replayed automatically.
API failures retain their bounded error code, status, retryability, safe field names, next actions, and correlation ID. Raw remote messages, request bodies, stack traces, file paths, and credential-provider errors are not emitted as diagnostics. Auth and tenant denials do not trigger broader lookups. Normal successful resource output can contain authorized customer information; handle stdout as application data, not a public log. Supplied access tokens are redacted if reflected in output.
What is not implemented
- Hosted OAuth login, human signup, account ownership verification, or token
refresh.
initperforms machine enrollment only, andclaimonly issues the invitation: accepting it, and every sign-in it needs, stays in the console. - Membership or API-key administration, billing, usage, or entitlement changes.
- Automatic DNS changes, operation polling, background workers, or flow execution.
- Customer-session token issuance from the CLI; credentials are never minted to stdout.
Flow create/version/publish commands manage stored definitions only. Inspect
capabilities for the server's actual execution status. A successful publish
does not mean that a flow is executing against conversations.
Validate
pnpm checkChecks cover all 16 single-call command mappings through the real SDK, the whole
init step machine and both claim forms against loopback onboarding and
management fixtures with state in a temporary home, input and credential boundaries, denial/redaction behavior, deadlines and cancellation,
the compiled executable against a synthetic loopback API, and an unpacked npm
tarball with its pinned production dependencies installed offline using a
verification-only copy of this repository's frozen lockfile. That lockfile is
not shipped in the tarball. These checks do not certify a deployed server's
tenant isolation or production availability.
