Start the read-only local Web Console on 127.0.0.1:8765:
aikito web
aikito web --port 9000
aikito web --no-openThe Console browses canonical resources and governance status. It does not modify workspace files or expose MCP secret values.
Aikito uses an operation-first command structure. Run
aikito <command> --help for the complete options supported by the installed
version.
| Command | Purpose |
|---|---|
aikito init workspace [path] |
Initialize a new workspace or connect an existing one, detect installed Agents, and remember an explicit path |
aikito path workspace |
Print the resolved active workspace path |
aikito migrate workspace-resources [--dry-run] |
Preview or apply the required one-time migration to per-resource Agent and subagent files |
aikito import workspace <source> [--dry-run] [--verbose] |
Preview or import canonical resources from another workspace into the active workspace |
aikito git [args...] |
Run git commands directly in the active Aikito workspace |
aikito init project [name] [path] [--description <text>] |
Register a code project and synchronize its .agents/ runtime |
aikito add skill [name] [--from <path>] [--force] [--project <projects>] [--global] [--sync] |
Create or import a canonical skill; defaults to current project when inside one, or workspace global if outside or with --global |
aikito add subagent [name] [--from <path>] [--description <desc>] [--agents <list>] [--sync] [--force] |
Create a canonical subagent skeleton or import from external markdown source; use --force with --from to replace |
aikito add mcp [name] [--from <source>] [--transport {stdio,remote}] [--command <cmd>] [--url <url>] [--agents <list>] [--sync] [--force] |
Create a canonical MCP server configuration or import from an external file (.json, .toml) or remote URL |
aikito adopt [path] [--dry-run] [--verbose] [--skip <resource>] |
Preflight existing local configuration, then import it only when the complete plan is safe |
aikito status |
Show the synchronization dashboard |
| `aikito diff [project | mcp |
aikito sync [--dry-run] [--verbose] |
Preflight all host-compatible resources together, then synchronize only when the complete plan is safe |
aikito sync global [--dry-run] |
Synchronize or preview global instructions and skills |
aikito sync project [name] [path] [--dry-run] [--force] |
Synchronize or preview a project's .agents/ directory (detected from cwd if omitted) |
aikito sync mcp |
Synchronize MCP entries |
aikito sync subagents |
Render and synchronize subagents |
aikito auth mcp <agent> <server> |
Authenticate a configured MCP server |
aikito show mcp [server] [--agent agent] [--live] |
Inspect MCP configuration or compare a server's live tool discovery across Agents |
aikito show subagents [target] [--agent agent] |
Inspect the subagent matrix, drill into platform options per agent, or print the canonical Markdown file |
| `aikito show project [name | .]` |
| `aikito show instructions [global | project |
aikito show inbox [target] |
Print raw markdown content of an inbox note, or list all inbox notes if target is omitted |
aikito edit inbox <target> |
Open an inbox note in $VISUAL or $EDITOR |
aikito rm inbox <target> |
Remove an inbox note file |
| `aikito show memory [target] [--project | --all]` |
aikito show skill [target] |
Print a skill's SKILL.md file, or list all skills if target is omitted |
aikito rename memory <target> <new-name> |
Rename a memory note and refactor inbound wikilinks |
aikito rm memory <target> |
Remove a memory note and scan for inbound wikilinks |
aikito rm skill <name> [--project <projects>] [--force] [--sync] |
Remove a skill globally or unregister it from specific project(s) |
aikito rm subagent <name> [--sync] |
Remove a subagent and unregister it from workspace |
aikito rm mcp <name> [--sync] [--force] |
Remove a canonical MCP server configuration from workspace |
aikito edit memory <target> |
Open a memory note in the configured editor |
aikito maintain memory [global|<project>|.] [--agent <name>] |
Launch an Agent to review one complete memory scope and propose maintenance before making changes |
| `aikito edit instructions [global | |
aikito edit skill <target> |
Open a skill's SKILL.md in $VISUAL or $EDITOR |
aikito edit subagent <target> |
Open a subagent's instruction markdown in $VISUAL or $EDITOR |
aikito doctor [--fix] |
Run deep workspace diagnostics and repair supported configuration issues |
aikito remote bind <endpoint> [--token-env <VAR>] [--workspace <PATH>] |
Bind the workspace to an external remote store and pin its identity |
aikito remote sync (--dry-run | --apply) [--verbose] [--workspace <PATH>] |
Preview or synchronize local workspace resources with the bound remote store |
aikito remote watch [--poll-interval <SEC>] [--debounce-ms <MS>] [--once] [--verbose] [--workspace <PATH>] |
Continuously synchronize local workspace changes and remote updates |
aikito remote start [--workspace <PATH>] [--mode {auto,system,process}] |
Start background automatic synchronization service |
aikito remote stop [--workspace <PATH>] [--mode {auto,system,process}] |
Stop background automatic synchronization service |
aikito remote status [--workspace <PATH>] [--json] [--mode {auto,system,process}] |
Show status of remote binding and background synchronization |
aikito remote credential {set,list,path} |
Manage credentials in secure user configuration storage |
aikito completion zsh|bash|fish|powershell |
Print a shell completion script |
aikito completion candidates projects|skills|subagents|mcps|memories|memory-completions|inbox|inbox-completions|paths [prefix] |
List dynamic completion candidates |
aikito version [-c|--check] [--force] [--json] |
Print the CLI version and check for available updates |
Aikito allows synchronizing workspace resources with an external remote store. To configure synchronization, first bind the workspace to an endpoint:
aikito remote bind https://remote.example.com/v1/remote
aikito remote bind https://remote.example.com/v1/remote --token-env CUSTOM_TOKENThe binding persists the endpoint and pinned sync_id locally in .local/state/aikito/workspace-reconcile/binding.json.
Credentials are never written to the workspace; Aikito references the environment variable name (default: AIKITO_REMOTE_TOKEN) or resolves from secure user credential storage.
Background services running outside an interactive shell can securely resolve tokens from user configuration storage (~/.config/aikito/credentials with 0600 permissions) or OS keychains:
# Store a bearer token securely in credentials file (prompts interactively with hidden input)
aikito remote credential set AIKITO_REMOTE_TOKEN
# Or pass token non-interactively via standard input
echo "secret-token-value" | aikito remote credential set AIKITO_REMOTE_TOKEN --stdin
# Or store directly into the operating system keychain / keyring (macOS / Linux)
aikito remote credential set AIKITO_REMOTE_TOKEN --keychain
# Native OS keychain tools can also be populated manually:
# macOS: security add-generic-password -U -s aikito -a AIKITO_REMOTE_TOKEN -w "secret-token-value"
# Linux: echo "secret-token-value" | secret-tool store --label="aikito" service aikito key AIKITO_REMOTE_TOKEN
# (Note: Windows is not currently supported for --keychain; use the secure credentials file instead.
# On macOS, `security -w <value>` passes the token as a CLI argument during execution; for maximum confidentiality,
# use the credentials file with 0600 permissions or standard environment variables.)
# List configured credential names (values are masked)
aikito remote credential list
# Display path to the secure credentials file
aikito remote credential pathPreview planned changes before applying:
aikito remote sync --dry-run
aikito remote sync --dry-run --verboseDry-run mode inspects local and remote snapshots and reports planned creations, updates, deletions, conflicts, and blocked resources without modifying local files or the remote store.
To apply the synchronization plan:
aikito remote sync --apply
aikito remote sync --apply --verboseReconciliation transfers mutations transactionally between the local workspace and remote store. Unresolved conflicts and blocked resources remain untouched while safe resources are applied.
Run the foreground auto-sync worker to continuously synchronize changes between the local workspace and the remote store (useful for debugging):
aikito remote watch
aikito remote watch --poll-interval 5.0 --debounce-ms 500
aikito remote watch --onceRun automatic synchronization as an operating system background service:
# Start background service (auto-detects macOS launchd, Linux systemd --user, or Windows Task Scheduler)
aikito remote start
# Inspect service liveness, PID, revision, conflicts, and pending commits
aikito remote status
aikito remote status --json
# Gracefully stop background service and disable autostart
aikito remote stop
aikito remote disableThe background service:
- Registers native OS background definitions (macOS LaunchAgent in
~/Library/LaunchAgents/, Linux systemd unit in~/.config/systemd/user/, Windows Scheduled Task viaschtasks). - Reuses the worker lifecycle lock to ensure idempotency and prevent duplicate workers.
- Gracefully handles termination via stop requests with a 35-second termination window (covering the 30-second HTTP timeout), ensuring in-flight rounds and pending journals finish safely before stopping.
- Disables and removes autostart registrations on stop/disable so services do not respawn on subsequent logins.
- Never logs sensitive tokens or file bodies.
To move resources from an existing workspace to the active workspace, first
review the plan, then run the same command without --dry-run:
aikito import workspace /path/to/source-workspace --dry-run
aikito import workspace /path/to/source-workspaceThe importer creates missing projects from their canonical workspace files;
their code directories may be cloned and synchronized later. Non-conflicting
resources are applied in one transaction; unresolved conflicts keep the target
unchanged and the command exits with status 2. Actual partial application is
reported as [PARTIAL]. A dry run with unresolved conflicts also exits with
status 2 but writes nothing. Path safety problems and snapshot findings still
block the entire import with status 1 and no resource writes. Status 0 means
there are no unresolved conflicts or blockers. Status 2 reports unresolved
conflicts, including a dry run or an import with no accepted changes; it does
not by itself guarantee that files were written. The source workspace is read only. The default output lists
one CREATE or UPDATE line per changed file and blockers with a summary;
--verbose adds the affected resource IDs and lists unchanged and skipped
source items. Resolve individual conflicts by resource ID, repeating the
options for multiple resources:
aikito import workspace /path/to/source-workspace --dry-run \
--keep-target memory:notes/local-policy.md \
--take-source skill:reviewer
aikito import workspace /path/to/source-workspace \
--keep-target memory:notes/local-policy.md \
--take-source skill:reviewer--keep-target skips importing the resource, whether it would be created,
updated, or conflicted. An existing target stays unchanged; an absent target
stays absent. --take-source resolves conflicts only and does not override a
customized target when the source is still at its template. IDs must belong to
the source's supported resources, and an ID cannot have opposite choices. Choices are scoped to that
invocation, so retaining a differing target requires the same choice on a later
import or manually making the resources agree. Selecting the source cannot
bypass reference or safety checks. Changes with missing references are reported
as conflicts and skipped along with their dependent changes. Shared TOML writes
include only accepted fields and collection members.
After importing, preview runtime synchronization with
aikito sync --dry-run, bind any offline project with
aikito sync project <name> <path>, and review the workspace with aikito git.
aikito --help
aikito sync --help
aikito status --help
aikito --versionCommands differ in their effect:
status,diff,show,completion, andadopt --dry-runare read-only;gitforwards arbitrary Git commands and arguments directly to the active workspace;init workspacecreates or updates a recognized workspace;migrate workspace-resources --dry-runpreviews all changes and blockers without writing; the command without--dry-runapplies the migration transaction;import workspace <source> --dry-runpreviews each resource action without writing; the command without--dry-runapplies the reference-safe subset, preserving unresolved conflicts; global safety findings still prevent all writes;init projectcreates an idempotent canonical project skeleton and its runtime links;addcreates a canonical resource skeleton and performs required registration;adoptpreflights all detected resources, then writes imported resources into the workspace after backup only when the complete plan is safe;syncpreflights every workspace scope, then writes managed Agent or project runtime configuration only when the complete plan is safe;editdelegates a canonical memory, skill, instruction, or subagent file to an external editor.maintain memorylaunches an interactive Agent whose prompt requires confirmation before writes.
Bare aikito sync --dry-run prints a concise read-only plan; add --verbose for
every item and path. Targeted project, MCP, and subagent sync commands also
support --dry-run. Consult the Safety model before applying
changes to an existing setup.
doctor compares registered Agents with the current bundled registry schema.
Missing fields are warnings; doctor --fix adds bundled defaults without
replacing existing values. Installed supported Agents missing from the registry
are also reported and can be added by doctor --fix.
Registered bundled Agents that are no longer detected are reported as offline
and preserved safely in agents/<name>.toml for multi-host roaming.
It also reports each project's native instruction, skill, and memory runtime
issues. Missing resources point to sync project; conflicts remain read-only
and point to show project for review. Findings are aggregated per project;
when missing resources and conflicts coexist, the conflict action wins.
The Adoption section uses the same structured findings as adopt, including
the affected resource, source, reason, and exact review or skip command.
Adoption findings are warnings: doctor and doctor --fix never import or skip
resources.
The LocalState section checks host-local project skill copy records under
~/.local/state/aikito/project-skills/. Records for temporary workspaces and
checkouts that both no longer exist include the cleanup command
aikito doctor --fix. Cleanup rechecks bindings under the writer lock and is
deferred while transaction journals are present. Unavailable non-temporary
paths, malformed records, and symlinks are reported and preserved. Ordinary
doctor, including JSON output, never removes or rewrites these records.
When one detected resource is intentionally out of scope, repeat
--skip instructions, --skip mcp/<name>, or --skip subagent/<name> as
needed. Skips apply only to that invocation and are printed in the plan. Unknown
resource names fail instead of being ignored; unreadable or malformed source
configuration remains a plan-level error and cannot be skipped.
adopt also accepts --skip agent/<name> for a planned built-in Agent
registration. Skip its dependent new MCP or subagent resources too; otherwise
preflight blocks the entire import.
status is the compact dashboard: its Memory Status column combines the
presence of canonical note directories and runtime connection health, and the
legend explains any warning symbols. Use
show project <name> to inspect the exact runtime resource paths and link
issues for one project.
See the Python API Reference for Project.load(),
Project.prepare(), Project.add_path(), PreparedProject, and the full
exception hierarchy.
Project.prepare() has no CLI wrapper. Operators use
aikito sync project [name] for manual project synchronisation and path
registration (detected from cwd if omitted).
aikito maintain memory defaults to the project whose locally present path
contains the current directory and launches the codex runner configured in
agents/<name>.toml. A named project uses the candidate that contains the current
directory; if you are not inside one, a project with a single local path still
uses that path, while multiple local paths require running the command from one
of them. Use global or a registered project name to select another scope, and
--agent to choose codex, claude-code, agy, opencode, or
github-copilot.
Custom Agents can define [agents.<name>.runner] with a command array.
Supported placeholders are {prompt}, {workdir}, {scope}, and
{memory_dir}. Optional [agents.<name>.runner.env] string values override
the inherited process environment and support the same placeholders:
[agents.codex.runner.env]
HTTPS_PROXY = "http://127.0.0.1:1234"Runner environment values belong to the user workspace and must not be added to the source repository. Keep only safe commented examples in source-controlled templates, and never rely on repository publication as a secrets store.
After aikito status or aikito doctor reports drift, inspect drifted managed resources:
# High-level drift index across the workspace
aikito diff
# Drill-down into a specific project (defaults to cwd if omitted inside a project)
aikito diff project [project]
aikito diff project <project> <skill>
aikito diff project <project> <skill> <file>
# Specific MCP server or subagent
aikito diff mcp <agent> <server>
aikito diff subagent <agent> <name>
# Full unified diff dump across all drifted resources
aikito diff --allThe bare aikito diff command outputs a high-level drift index showing which MCPs, subagents, and projects have drifted, without dumping raw unified diffs. To inspect full diffs, drill down by project/skill/file or use --all to print all unified diffs at once. MCP credentials and sensitive headers are redacted. Binary project skill files are reported without printing their contents. Missing resources and unmanaged conflicts remain status findings and are not rendered as drift diffs.
Targeted commands inspect only their resource kind, so unrelated MCP configuration errors do not block project or subagent diffs. Project indices group changes by checkout path, and full diffs identify the checkout in each resource label. File targets accept / or \ separators and equivalent relative paths such as ./scripts/check.py.
Aikito calls this resource “instructions” and stores its canonical content in
AGENTS.md for ecosystem compatibility.
Without a target, show how each Agent is connected to global instructions,
followed by a compact Projects section. A project with missing or empty
canonical instructions is shown as -; otherwise its runtime link is shown
as linked, missing, or conflict. Provide global, a project name, or .
to print raw Markdown content:
aikito show instructions
aikito show instructions global
aikito show instructions example
aikito show instructions .
aikito edit instructions
aikito edit instructions example
aikito edit instructions .. resolves the registered project containing the current directory and notes
that global instructions are also active. If target is omitted for aikito edit instructions,
it resolves the project containing the current working directory, falling back to global
when run outside any project.
inbox/ acts as a staging directory for raw notes captured from browser AI conversations before they are curated into durable memory.
List inbox notes sorted by modification time (Name and Modified):
aikito show inboxPrint the raw Markdown content of an inbox note by exact name or unique prefix:
aikito show inbox perplexity-ai-positioning
aikito show inbox perplexityOpen an inbox note in the configured editor:
aikito edit inbox perplexity-ai-positioningRemove an inbox note after reviewing or curating it:
aikito rm inbox perplexity-ai-positioningThe inbox directory defaults to <workspace>/inbox and can be customized in config.toml:
[inbox]
path = "inbox"Global workspace behavior is governed by <workspace>/config.toml:
# <workspace>/config.toml
[memory]
# Days after which an untouched durable memory note is flagged as stale (default: 30)
stale_days = 30
[inbox]
# Staging directory for incoming distilled notes (default: "inbox")
path = "inbox"
[update]
# Enable or disable automatic background update checks and CLI notifications (default: true)
check = trueAikito performs lightweight, non-blocking version checks against PyPI and GitHub releases using a 24-hour local cache.
To disable automatic upgrade notifications:
- In
<workspace>/config.toml: set[update] check = false - In the shell environment: set
export AIKITO_NO_UPDATE_NOTIFIER=1orNO_UPDATE_NOTIFIER=1
To inspect version and update status manually:
# Print current version (plus cached update notice on stderr if available)
aikito version
# Check for updates against remote source (reuses cache if checked within 24h)
aikito version --check
# Bypass cache and force an immediate remote check
aikito version --check --force
# Machine-readable output in JSON format
aikito version --jsonList each registered project's path, synchronization mode, instructions, selected skill count, project memory note count, context footprint estimate, and aggregate sync status:
aikito show projectsInspect one project's canonical and project directories, configuration, and sync issues when present:
aikito show project
aikito show project example
aikito show project .When inside a registered project directory, aikito show project defaults to the
current project. An explicit . also resolves the current project. Outside any
registered project, omitting the argument lists all projects (equivalent to
aikito show projects).
Initialize a new workspace or connect an existing one:
# Brand new workspace:
aikito init workspace ~/aikito
# Existing workspace:
aikito init workspace <workspace-path>
aikito syncRegister a code project from its directory. The directory name becomes the project name by default:
cd ~/code/example
aikito init projectBoth values can be explicit:
aikito init project example ~/code/example \
--description "Example service workspace"Project initialization creates agent.toml, AGENTS.md, and the project
memory skeleton under <workspace>/projects/<name>/, then synchronizes the target
project's .agents/ runtime and each workspace-registered Agent's native project
instruction path. Targets shared by multiple agents are linked once.
Existing unmanaged files are reported as conflicts and are never replaced. The
initial AGENTS.md is empty until project-specific instructions are added.
The optional description is display-only metadata stored in agent.toml.
Initialization is idempotent. A
project name already bound to another path, or unmanaged resources at a target
runtime path, is reported as a conflict rather than overwritten.
Aikito ships its own completion scripts so you do not need third-party packages.
Zsh — add one line to ~/.zshrc:
eval "$(aikito completion zsh)"Bash — add one line to ~/.bashrc or ~/.bash_profile:
eval "$(aikito completion bash)"Fish — install the completion file once:
aikito completion fish > ~/.config/fish/completions/aikito.fishPowerShell — add one line to your $PROFILE:
Invoke-Expression (& aikito completion powershell | Out-String)Completion covers all commands, subcommands, and options statically. When tab-completing a memory note, skill name, or project name, Aikito calls a lightweight internal interface that reads only the local workspace files with no network requests or expensive diagnostics:
aikito completion candidates projects
aikito completion candidates skills
aikito completion candidates subagents
aikito completion candidates mcps
aikito completion candidates memories
aikito completion candidates inbox-completions
aikito completion candidates paths agentPath arguments combine normal local filesystem completion with basename-prefix matches from the Aikito workspace and registered project roots. Hidden and generated dependency directories are skipped, and ambiguous matches remain visible for explicit selection.
Installation via brew install lsaint/tap/aikito automatically installs
Zsh, Bash, and Fish completions without modifying ~/.zshrc.
With a bound HTTPS Store, submit a short-lived ownership challenge to the same service. Select the account independently of the challenge file:
aikito remote claim --workspace ~/aikito --challenge ownership-challenge.json \
--account account-123This uses the existing Store credential reference. It does not log into an
account, export content keys, enable synchronization or grant access to Memory.
The service must support the claim endpoint and issue the challenge from an
authenticated account session. A challenge file alone does not authenticate its
account label; verify the account ID in your authenticated session before passing
--account. The service checks the expected account before changing ownership.
The file contains version 1, challenge_id, account_id, store_id, sync_id
and UTC Unix expires_at. Unknown fields, wrong identity/account, expired or
more than five-minute challenges are rejected before resolving credentials.
The destination is derived exclusively from the existing HTTPS binding; the
file cannot choose a URL. Requests never follow redirects, and response loss is
reported as claim_outcome_unknown without retries. Check the account's Store
status before attempting another claim. Workspace content, Base, binding and
pending state stay unchanged.
These commands manage a local device key. Local header recovery does not enable sync by itself; use the explicit encrypted path below. Ordinary sync retains its unsupported-format guard, and plaintext migration remains unavailable.
python -m pip install 'aikito[encrypted]'
aikito remote key path --workspace ~/aikito
aikito remote key recover --header recovery-header.json --sync-id STORE_SYNC_ID --workspace ~/aikitoThe recovery command prompts without echo. Automation must provide an explicit
--recovery-fd; the code must not appear in arguments or environment variables.
The header is public metadata, while the recovery code is secret. Device keys are
saved outside workspace and Git; home backups may include them. See the
Remote Store Boundary
for storage and recovery limits.
Files remain the default. On a bound, unlocked encrypted Store, explicitly select OS protection or return to a file:
aikito remote key storage --workspace ~/aikito --backend native
aikito remote key storage --workspace ~/aikito --backend filemacOS uses an unlocked default Keychain; Windows uses current-user DPAPI; Linux
requires secret-tool, gdbus, a session D-Bus and an unlocked default Secret
Service collection. Missing tools, a locked store or access denial stop with
key_storage_unavailable. There is no automatic fallback or unlock prompt.
The operation authenticates the remote header, reads back the protected key and
atomically switches the local record. It does not change remote content or Base.
Native items are retained when switching to files because other workspaces may
use them. Older clients cannot read native records; explicitly switch to files
before downgrading.
If the native backend is unavailable, use the recovery code to explicitly restore file storage. A verified header and matching Vault key are required:
aikito remote key recover --workspace ~/aikito --header recovery-header.json \
--sync-id STORE_SYNC_ID --file-storageFile storage uses owner-only permissions. Home backups include the raw key file
or its protected native reference/blob. DPAPI blobs depend on the user's Windows
profile; a copied keychain reference alone cannot unlock another machine. Keep
the recovery code separately. Homebrew installs the encrypted runtime by default;
other Python installations opt in with aikito[encrypted].
For an initialized workspace with an existing remote binding and a recovered device key, inspect one read-only discovery round:
aikito remote key inspect --workspace ~/aikitoRepeat until the output says complete. Each invocation authenticates the format
header and verifies at most 32 business resources within the shared fetch byte
budget. Private resources bootstrap project identities before project Memory is
discovered. Output includes counts and revision, without content or logical names.
The authenticated local map allows separate CLI processes to resume; unchanged
verified descriptors are not downloaded again.
This command does not change remote data, business files, bindings, pending or
Replica Base. An incomplete view cannot authorize deletions or writes. Ordinary
remote sync still refuses encrypted stores; scoped read export is described below. A migrating header pauses inspection.
Use the explicit encrypted commands with an existing binding to initialize an empty Store. Initialization refuses any Store containing plaintext resources. The recovery code is generated independently, delivered once to a secure terminal or explicit output descriptor, and never persisted in the workspace or Git.
aikito remote key initialize --workspace ~/aikito
aikito remote key sync --dry-run --workspace ~/aikito
aikito remote key sync --apply --workspace ~/aikitoAutomation must provide --recovery-output-fd to initialization; keep that channel
private. On a fresh device, use the Store Token environment variable and enter the
recovery code securely to recover and bind directly:
aikito remote key recover --endpoint https://remote.example/v1/stores/STORE/remote --workspace ~/aikitoAn optional --sync-id checks the expected Store identity. The default token source
is AIKITO_REMOTE_TOKEN, changeable with --token-env. Recovery codes only enter
through the secure prompt or explicit --recovery-fd; --header local recovery
continues to require --sync-id and does not create a binding.
Encrypted sync discovers unknown descriptors in bounded rounds before planning business changes. Preview does not write discovery, Base, pending or remote data. Apply encrypts uploads before persisting a request. Delivery uncertainty retains that exact request; rerun the command to resolve its receipt or resend identical bytes. Captured uploads advance logical Base without overwriting newer local edits. Later applied local edits win and replaced remote versions are archived locally. Initialization also retains its public header request across response loss. A CAS loser must recover the winning Vault; retrying cannot replace it.
Ordinary remote sync and ordinary bind continue to guard encrypted Stores. Use
the explicit encrypted path after recovery. Use the explicit migration commands below for plaintext representation changes.
Historical server cleanup has a separate administrator boundary.
Preview an existing bound plaintext Store after ordinary synchronization and a clean, committed workspace Git baseline:
aikito remote key migrate --dry-run --workspace ~/aikitoBefore writing, upgrade every device connected to the Store and stop automatic
synchronization on all devices. Confirm this explicitly with
--confirm-devices-upgraded; without it, apply stops with
encrypted_migration_devices_required before opening the remote. This is an
operator confirmation, not automatic verification of other devices. No published
release is required. The explicit operations are:
aikito remote key migrate --apply --confirm-devices-upgraded --workspace ~/aikito
aikito remote key migrate --apply --confirm-devices-upgraded --takeover --workspace ~/aikito
aikito remote key migrate --apply --confirm-devices-upgraded --rollback --workspace ~/aikitoInitial migration requires matching local resources, Replica Base and remote
revision, no pending commit, byte-identical portable payloads and a clean Git
baseline. Preflight checks ciphertext expansion, the peak mixed manifest and
atomic dependency-group budgets before publishing the marker. Migration preserves
business files, logical Base, Store identity and the ordinary client's receipt.
The one-time recovery code uses a secure terminal or explicit
--recovery-output-fd. Keep this output private.
Each round copies one dependency group before deleting old resources in reverse
dependency order. The authenticated migrating header pauses ordinary devices.
Ownership is a CAS epoch/client/token fence with no automatic timeout. An unlocked
new device can reconstruct progress from the remote and explicitly take over;
the old owner stops on a changed fence. --max-rounds 1..1024 bounds an invocation;
exit status 2 means paused, so rerun without --takeover to resume the same epoch.
Requests are persisted before dispatch and receipt lookup resolves uncertainty
before identical retries. The local migration journal is itself encrypted,
including rollback requests that necessarily carry plaintext on the wire.
Rollback explicitly restores the plaintext representation and removes the marker only after the whole plaintext graph is complete. It does not reset business files or Git history. Migration and rollback affect the current snapshot; old server objects, backups and filesystem snapshots need separate administrator retention or cleanup. Scoped read export is described below.
Fetch a recipient public key from an explicit HTTPS origin before creating a scoped export. This command works without the optional encrypted dependency:
aikito remote key fetch --workspace ~/aikito \
--origin https://recipient.example.com --output recipient.jsonThe origin must have no path, query, userinfo or fragment. The fixed request is
GET /v1/keys/recipient; TLS certificates are verified, redirects are rejected,
and no Store token or browser cookie is sent. The response is a bounded canonical
recipient JSON document matching the format below.
First use automatically pins the key ID and public key under the local config
base's aikito/remote-recipients/, outside the selected workspace. Repeating with
the same identity succeeds. Any change to either field stops without creating an
output or changing the pin. After independently establishing that the change is
expected, explicitly accept it with a fresh output path:
aikito remote key fetch --workspace ~/aikito \
--origin https://recipient.example.com --output recipient-new.json \
--accept-key-changeThere is no manual fingerprint comparison requirement. First use trusts the chosen origin and its TLS identity; losing or deleting local pins loses that continuity. Corrupt, linked or unsafe pin records fail closed even with the acceptance flag. Pins are owner-only and serialized against other local writers. The command never overwrites an output file, changes a Remote binding or grants content access. A failed output write can follow a successfully saved pin; retry using a fresh output path. The resulting document can be passed to key export.
Export one explicitly selected existing project Memory collection to a trusted
recipient's X25519 public key. This requires aikito[encrypted] with
cryptography>=47, an existing binding and the external device key:
aikito remote key export --workspace ~/aikito \
--collection project/demo/memory \
--recipient recipient.json --authorization request.json \
--output scoped-read.jsonThe command verifies the Store header, parent Project and one Memory sample,
then seals only the explicitly selected collection keys. The default permission
is read, exporting only its content key. It refuses private, global Memory,
other resource types, empty collections and migrations.
There is no implicit project, wildcard or plaintext-key output. The output is a
new owner-only encrypted file; existing files and links are never overwritten.
Remote data, discovery checkpoints, pending and Replica Base are unchanged.
Both inputs use canonical JSON (sorted keys, compact UTF-8, no trailing newline).
The recipient document contains exactly version:1,
algorithm:"hpke-x25519-hkdf-sha256-a256gcm", key_id and public_key (standard
Base64 raw 32-byte key). Obtain this document from a trusted source; this local
export command does not discover or pin a remote recipient; use remote key fetch
for HTTPS discovery with local trust continuity.
The authorization request contains exactly version:1, account_id, store_id,
sync_id, vault_id, collection_id, recipient_key_id, permissions:["read"],
grant_id, nonce (Base64 32 bytes) and expires_at (future UTC Unix seconds).
Store, grant and recipient key identifiers use 1–128 ASCII letters,
digits, dots, underscores or hyphens. Account identifiers also allow colons. Select the collection explicitly and match
its name and recipient key ID to the request. The encrypted package binds every
request field, Vault/Store identity, collection Tag, recipient public key hash and
fixed parent opaque ID. Project names and the content key remain inside HPKE.
Export creates a local package; it does not activate a grant, prove account ownership or consume a one-time nonce. Receivers must separately authenticate the sender and trusted request, verify Store ownership, reject replay, test resource decryption and enforce expiry/revocation. HPKE Base mode does not authenticate senders. A recipient holding the content key can read the entire selected collection, including future content until key rotation; expiry cannot erase copied keys. Private resources and other projects have independent keys.
For independent write delegation, obtain a separate authorization whose permissions
are exactly ["read","write"] and explicitly select write on both commands:
aikito remote key export --workspace ~/aikito --collection project/demo/memory \
--permission write --recipient recipient.json --authorization write-request.json \
--output scoped-write.json
aikito remote key submit --workspace ~/aikito --origin https://recipient.example.com \
--permission write --package scoped-write.json --authorization write-request.json \
--account account-123 --collection project/demo/memoryA write request is rejected by the default read command before loading keys or
resolving a Store credential; selecting write against a read request is also rejected.
Write material contains only this collection's content, resource-ID and fingerprint
subkeys, bound to the independent aikito.scoped-write-export HPKE info domain.
It does not contain the Vault root, collection master, tag key or private keys.
The fixed parent opaque ID comes from the authenticated local parent Project.
Receivers must verify all three keys against a real sample and persist/revoke the
write grant independently. This export does not write any Memory or imply that
consumer write tools are available.
Submit an existing sealed package to an explicit HTTPS recipient origin:
aikito remote key submit --workspace ~/aikito \
--origin https://recipient.example.com --package scoped-read.json \
--authorization request.json --account account-123 \
--collection project/demo/memoryThis command works without the encrypted extra. First obtain and inspect the
recipient's authorization request, then use remote key fetch and remote key export as above. Choose the account and collection independently; submission
checks both against the request before resolving the bound Store credential.
It also checks the binding's Store/sync identity, all package context fields,
and a freshly fetched public key against the existing origin pin. Missing or
changed pins stop submission; accepting a key change requires a separate fetch.
The command sends one authenticated POST to /v1/stores/{store}/grants on the
explicit origin, using the existing Store Token. It verifies TLS, sends no
browser Cookie, refuses redirects, and never retries a submission. Keep this
origin distinct from the Remote endpoint when the recipient uses separate
listeners. Request/package files must be canonical JSON. No workspace, Remote,
pending or Replica Base data is written.
A successful HTTP 202 receipt must report active: the receiver saved the
scoped grant with the exact requested permissions. Verification-only receipts
are rejected; the CLI reports activation only after validating the complete receipt. An active grant lasts until its stated expiry
or explicit receiver-side revocation, independently of the submitting device.
Content endpoints and authorization for individual consumers are separate
receiver capabilities.
A rejected request may already be consumed; a lost or malformed response reports
export_outcome_unknown. Check the receiver's grant list before requesting a
fresh authorization. Submission never retries or follows redirects. Receivers
must enforce revocation and must not restore revoked keys from backups.
