@gubkin-labs/aleph-cli
v1.16.1
Published
Cross-platform CLI for publishing and managing Aleph agents
Readme
Aleph CLI
Publish and manage Aleph agents from a terminal or CI workflow.
npx @gubkin-labs/aleph-cli login
npx @gubkin-labs/aleph-cli agents push ./my-agent
ALEPH_API_KEY=... npx @gubkin-labs/aleph-cli agents sync . --json
printf '%s' "$TOKEN" | ALEPH_API_KEY=... npx @gubkin-labs/aleph-cli vault set GH_TOKEN --value-stdinGlobal installation and the standalone release binaries expose the same
aleph command.
Authentication
aleph login opens the Aleph browser authorization page and stores the
resulting session in macOS Keychain, Windows Credential Manager, or the Linux
Secret Service. After approval, the CLI prompts for Personal or an
organization membership and calls Better Auth set-active on that session so
agents list / pull / sync use the same org scope as the web app. Use
--org <id-or-slug> or --personal to skip the picker (required for
non-interactive / --json login when you need an org). Switch later with
aleph org list and aleph org switch [id-or-slug] (or --personal).
aleph auth status reports the active scope and organization.
CI should provide a user or organization API key through ALEPH_API_KEY. A
--api-key flag takes precedence, followed by the environment variable and then
the stored browser session. Organization API keys are already org-scoped;
aleph org switch requires a browser session.
The API origin defaults to https://api.aleph-agent.com; override it with
ALEPH_API_URL or --api-url.
Vault
aleph vault set <name> creates or updates a vault value without printing the
value. By default it targets the authenticated user's vault; use
--org <id-or-slug> or --team <id> for a scoped vault. Pass
--value <value> for local use, or
prefer --value-stdin for CI so the secret is not present in command arguments:
printf '%s' "$ALEPH_REPOS_TOKEN" | aleph vault set GH_TOKEN \
--org aleph-featured-agents-org \
--value-stdin \
--description "Repository token for Aleph CMO"Agent manifests
Each bundle contains a sync-only aleph.json:
{
"agentId": "5c5b86cf-b0d6-4e30-a9a0-58292e3afd59",
"name": "Repository assistant",
"description": "Understands this repository.",
"labels": ["Engineering"],
"visibility": "private",
"icon": "cover.jpg",
"versionId": "11111111-1111-4111-8111-111111111111"
}aleph agents push [directory] publishes one bundle. aleph agents sync
[directory] discovers agents/*/aleph.json, direct child manifests, or a root
manifest shaped as { "agents": ["path/to/agent"] }.
aleph agents pull [directory] three-way merges the pinned (or latest) remote
version against the stamped base and local files, then stamps versionId.
Runtime-written memory/**/*.md files use this same flow. Pass a single agent folder, or a repo root /
agents/ directory (same discovery as sync) to pull every bundle. Prefer pull
over editing versionId by hand so Git matches the live bundle, not only the
pin id. Use --stamp-version-id when you only need the live pin stamped into
aleph.json and must keep local bundle edits. Conflicting text edits receive
standard conflict markers; conflicting binary files stop without overwriting
either side. Resolve and commit conflicts before syncing. Use --continue-on-error for
batch pulls.
agentId is a required UUID and the only create/update identity. On first
sync Aleph creates that exact ID; later syncs update it. If the field is
missing, the CLI prints a generated UUID and the exact JSON field to add.
When icon names a local JPEG, PNG, or WebP file, sync uploads it to
Aleph-managed storage (maximum 5 MB) and excludes it from the runtime bundle.
An explicit iconUrl remains supported and skips the upload.
Optional versionId tracks the base version Git last absorbed or published.
Push/sync fetches only that version's path/hash manifest, uploads added or
modified bytes, and represents deletions in metadata. The backend rebases the
delta onto the latest remote version, so unrelated remote memory changes do not
need to be pulled before publishing a local AGENTS.md edit. A same-path
remote/local change fails with a conflict and requires pull plus resolution.
Push/sync blocks when a remote already has versions and versionId is missing.
New agents (GET 404) may publish
without versionId; a successful push/sync stamps it.
Display names and .aleph/state.json are never identity fallbacks.
agents sync treats the discovered folders
as the source of truth: it permanently deletes any previously synchronized
bundle that is no longer present locally, then removes its saved ID. If that
agent was already deleted, sync reports a warning and continues. Synchronization
creates or updates metadata and uploads the runtime bundle. If its file paths,
bytes, and aleph.json metadata match the latest version, the CLI reports
unchanged and does not create, enable, disable, or repin a version. agentId
and versionId are excluded from this comparison because they are identity and
pin bookkeeping, not versioned metadata.
.aleph/state.json remains only
for reconciling bundle folders removed from Git.
Use --no-enable for catalog templates (disables new agents only;
existing agents keep their current enabled/disabled state — already-enabled
agents are repinned to the new version), --dry-run to validate without
mutations (gate checks still run), and --continue-on-error for batch processing.
Development
pnpm install
pnpm openapi
pnpm quality
pnpm package:binariesThe application API client is generated from Aleph’s /doc OpenAPI document.
Releases
Every push to main runs the release workflow after the full quality suite.
semantic-release publishes at least a patch release for every push; conventional
feat and breaking commits still select minor and major versions. The workflow
updates package.json, creates the version tag, and publishes the matching
GitHub release. It does not publish to npm.
Standalone executable packaging is intentionally separate because those
artifacts must be built on their corresponding operating-system runners.
After semantic-release commits a version, publish it manually from an authenticated local checkout:
git pull
pnpm install --frozen-lockfile
pnpm quality
npm publish --access publicThe release commit uses chore(release): <version> [skip ci], which satisfies
commitlint and prevents a recursive workflow run.
Commit messages
All commits must follow Conventional Commits 1.0.0:
<type>[optional scope][!]: <description>Examples: fix(auth): clear revoked sessions, feat(agents): add batch sync,
and feat(api)!: replace upload response. Husky validates messages locally,
and CI validates every commit in a push or pull request so bypassing local hooks
does not bypass the convention.
