Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .claude/rules/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ bun run cli version

## Startup Behavior

1. Deletes `process.env.DATABASE_URL` (prevent target repo's DB from leaking in)
2. Loads `~/.archon/.env` with `override: true`
3. Smart Claude auth default: if no `CLAUDE_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN`, sets `CLAUDE_USE_GLOBAL_AUTH=true`
4. Imports all commands AFTER dotenv setup
1. Loads `~/.archon/.env` with `override: true` (Archon's config wins over any Bun-auto-loaded CWD vars)
2. Smart Claude auth default: if no `CLAUDE_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN`, sets `CLAUDE_USE_GLOBAL_AUTH=true`
3. Imports all commands AFTER dotenv setup

## WorkflowRunOptions Interface

Expand Down
11 changes: 7 additions & 4 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,16 @@ Read the commit messages and the actual diffs (`git diff main..dev`) to understa
- `pyproject.toml`: update `version = "x.y.z"`
- `Cargo.toml`: update `version = "x.y.z"`

2. **Lockfile refresh** (stack-dependent):
2. **Workspace version sync** (monorepo only):
- If `scripts/sync-versions.sh` exists, run `bash scripts/sync-versions.sh` to sync all `packages/*/package.json` versions to match the root version.

3. **Lockfile refresh** (stack-dependent):
- `package.json` + `bun.lock`: run `bun install`
- `package.json` + `package-lock.json`: run `npm install --package-lock-only`
- `pyproject.toml` + `uv.lock`: run `uv lock --quiet`
- `Cargo.toml`: run `cargo update --workspace`

3. **`CHANGELOG.md`** — prepend new version section:
4. **`CHANGELOG.md`** — prepend new version section:

```markdown
## [x.y.z] - YYYY-MM-DD
Expand Down Expand Up @@ -141,8 +144,8 @@ Ask: "Does this look good? I'll commit and create the PR."
Only after user approval:

```bash
# Stage version file, lockfile, and changelog
git add <version-file> <lockfile> CHANGELOG.md
# Stage version file, workspace packages, lockfile, and changelog
git add <version-file> packages/*/package.json <lockfile> CHANGELOG.md
git commit -m "Release x.y.z"

# Push dev
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.3.4] - 2026-04-10

Binary env loading fix and release infrastructure improvements.

### Added

- **Docs site redesign**: logo, dark theme, feature cards, and enhanced CSS (#1022)

### Changed

- **Server env loading for binary support**: removed redundant CWD `.env` stripping — `SUBPROCESS_ENV_ALLOWLIST` and the env-leak gate already prevent target repo credentials from reaching AI subprocesses. Server now loads `~/.archon/.env` with `override: true` for all keys (not just `DATABASE_URL`), skips the `import.meta.dir` `.env` path in binary mode, and defaults `CLAUDE_USE_GLOBAL_AUTH=true` when no explicit credentials are set (#1045)
- **Workspace version sync**: all `packages/*/package.json` versions now sync from the root `package.json` during releases via `scripts/sync-versions.sh`

### Fixed

- **`archon serve` crash in compiled binaries**: the CWD env stripping + baked `import.meta.dir` path caused all credentials to be lost, triggering `no_ai_credentials` exit on every startup
- **CLI `version` command reading stale version**: dev mode now reads from the monorepo root `package.json` instead of the CLI package's own version field
- **Release CI web build**: fixed `bun --filter` syntax and added missing `remark-gfm` transitive dependencies for Bun hoisting

## [0.3.3] - 2026-04-10

Binary distribution improvements, new workflow node type, and a batch of bug fixes.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "archon",
"version": "0.3.3",
"version": "0.3.4",
"private": true,
"workspaces": [
"packages/*"
Expand Down
2 changes: 1 addition & 1 deletion packages/adapters/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/adapters",
"version": "0.1.0",
"version": "0.3.4",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/cli",
"version": "0.2.13",
"version": "0.3.4",
"type": "module",
"main": "./src/cli.ts",
"bin": {
Expand Down
27 changes: 7 additions & 20 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,13 @@ import { config } from 'dotenv';
import { resolve } from 'path';
import { existsSync } from 'fs';

// Strip all vars that Bun may have auto-loaded from CWD's .env.
// Bun auto-loads .env relative to CWD before any user code runs. The CLI
// runs from target repos whose .env contains keys for that app (ANTHROPIC_API_KEY,
// DATABASE_URL, OPENAI_API_KEY, etc.) — none of which should affect Archon.
// Strategy: parse the CWD .env without applying it, then delete those keys.
const cwdEnvPath = resolve(process.cwd(), '.env');
if (existsSync(cwdEnvPath)) {
const cwdEnvResult = config({ path: cwdEnvPath, processEnv: {} });
// If parse fails, cwdEnvResult.parsed is undefined — safe to skip:
// Bun uses the same RFC-style parser, so a file dotenv cannot parse
// was also unparseable by Bun and contributed no keys to process.env.
if (cwdEnvResult.parsed) {
for (const key of Object.keys(cwdEnvResult.parsed)) {
Reflect.deleteProperty(process.env, key);
}
}
}

// Load .env from global Archon config only (override: true so ~/.archon/.env
// always wins over any remaining Bun-auto-loaded vars)
// Load .env from global Archon config (override: true so ~/.archon/.env
// always wins over any Bun-auto-loaded CWD vars).
//
// Credential safety: target repo .env keys that Bun auto-loads from CWD
// cannot leak into AI subprocesses — SUBPROCESS_ENV_ALLOWLIST blocks them.
// The env-leak gate provides a second layer by scanning target repos before
// spawning. No CWD stripping needed.
const globalEnvPath = resolve(process.env.HOME ?? '~', '.archon', '.env');
if (existsSync(globalEnvPath)) {
const result = config({ path: globalEnvPath, override: true });
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/commands/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ interface PackageJson {
* Get version for development mode (reads package.json)
*/
async function getDevVersion(): Promise<{ name: string; version: string }> {
const pkgPath = join(SCRIPT_DIR, '../../package.json');
// Read root package.json (monorepo version), not the CLI package's own
const pkgPath = join(SCRIPT_DIR, '../../../../package.json');

let content: string;
try {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/core",
"version": "0.2.0",
"version": "0.3.4",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/docs-web/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@ export default defineConfig({
starlight({
title: 'Archon',
favicon: '/favicon.png',
logo: {
src: './src/assets/logo.png',
alt: 'Archon',
},
description: 'AI workflow engine — package your coding workflows as YAML, run them anywhere.',
head: [
{
tag: 'script',
content: `if(!localStorage.getItem('starlight-theme')){localStorage.setItem('starlight-theme','dark');document.documentElement.dataset.theme='dark';}`,
},
],
social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/coleam00/Archon' }],
editLink: {
baseUrl: 'https://github.com/coleam00/Archon/edit/main/packages/docs-web/',
Expand Down
2 changes: 1 addition & 1 deletion packages/docs-web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/docs-web",
"version": "0.2.12",
"version": "0.3.4",
"private": true,
"scripts": {
"dev": "astro dev",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ packages/cli/
┌─────────────────────────────────────────────────────────────────┐
│ cli.ts:15-31 Load environment │
Suppresses cwd .env → loads ~/.archon/.env only
│ cli.ts Load environment
Loads ~/.archon/.env with override: true
└─────────────────────────────────┬───────────────────────────────┘
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ description: AI workflow engine — package your coding workflows as YAML, run t
template: splash
hero:
title: Archon
image:
file: ../../assets/logo.png
alt: Archon Logo
tagline: Package your AI coding workflows as YAML. Run them anywhere — CLI, Web, Slack, Telegram, GitHub, Discord.
actions:
- text: Get Started
Expand All @@ -16,6 +19,8 @@ hero:
variant: minimal
---

import { Card, CardGrid } from '@astrojs/starlight/components';

## Install in seconds

:::code-group
Expand All @@ -42,8 +47,20 @@ docker run --rm -v "$PWD:/workspace" ghcr.io/coleam00/archon:latest workflow lis

Archon is a **workflow engine for AI coding agents**. Define multi-step development workflows in YAML — code review, bug fixes, feature implementation, testing — and run them with a single command.

- **Repeatable**: Package your best AI coding patterns as shareable YAML workflows
- **Isolated**: Each workflow runs in its own git worktree — no conflicts, no mess
- **Portable**: Run from CLI, Web UI, Slack, Telegram, GitHub, or Discord
- **Composable**: Chain workflow nodes into DAGs with dependencies, loops, and conditional logic
- **Multi-provider**: Works with Claude Code SDK and Codex SDK
<CardGrid>
<Card title="Repeatable" icon="document">
Package your best AI coding patterns as shareable YAML workflows
</Card>
<Card title="Isolated" icon="laptop">
Each workflow runs in its own git worktree — no conflicts, no mess
</Card>
<Card title="Portable" icon="puzzle">
Run from CLI, Web UI, Slack, Telegram, GitHub, or Discord
</Card>
<Card title="Composable" icon="setting">
Chain nodes into DAGs with dependencies, loops, and conditional logic
</Card>
<Card title="Multi-provider" icon="rocket">
Works with Claude Code SDK and Codex SDK
</Card>
</CardGrid>
7 changes: 3 additions & 4 deletions packages/docs-web/src/content/docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,12 +362,11 @@ When using `--branch`, workflows run inside the worktree directory.

## Environment

The CLI loads environment variables exclusively from `~/.archon/.env`. It does **not** load `.env` from the current working directory. This prevents conflicts when running Archon from target projects that have their own database configurations.
The CLI loads `~/.archon/.env` with `override: true`, so Archon's own config always wins over any env vars Bun auto-loads from the current working directory. Target repo env vars remain in `process.env` but cannot reach AI subprocesses — `SUBPROCESS_ENV_ALLOWLIST` blocks all non-whitelisted keys.

On startup, the CLI:
1. Deletes any `DATABASE_URL` that Bun may have auto-loaded from the target repo's `.env`
2. Loads `~/.archon/.env` with `override: true`
3. Auto-enables global Claude auth if no explicit tokens are set
1. Loads `~/.archon/.env` with `override: true` (Archon's config wins over CWD vars)
2. Auto-enables global Claude auth if no explicit tokens are set

## Database

Expand Down
12 changes: 5 additions & 7 deletions packages/docs-web/src/content/docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,21 +296,19 @@ Infrastructure configuration (database URL, platform tokens) is stored in `.env`

| Component | Location | Purpose |
|-----------|----------|---------|
| **CLI** | `~/.archon/.env` | Global infrastructure config (only source loaded) |
| **Server** | `<archon-repo>/.env` | Platform tokens, database |
| **CLI** | `~/.archon/.env` | Global infrastructure config (only source, loaded with `override: true`) |
| **Server (dev)** | `<archon-repo>/.env` + `~/.archon/.env` | Repo `.env` for platform tokens; `~/.archon/.env` overrides with `override: true` |
| **Server (binary)** | `~/.archon/.env` | Single source of truth (repo `.env` path is not available in compiled binaries) |

**Important**: The CLI loads `.env` **only** from `~/.archon/.env`. On startup, it explicitly deletes any `DATABASE_URL` that Bun may have auto-loaded from the current working directory's `.env`, then loads `~/.archon/.env` with `override: true`. This prevents conflicts when running Archon from target projects that have their own database configurations.
**How it works**: Both the CLI and server load `~/.archon/.env` with `override: true`, so Archon's own config always wins over any env vars Bun auto-loads from the current working directory. Target repo env vars remain in `process.env` but cannot reach AI subprocesses — `SUBPROCESS_ENV_ALLOWLIST` blocks all non-whitelisted keys.

**Best practice**: Use `~/.archon/.env` as the single source of truth. If running the server, symlink or copy to the archon repo:
**Best practice**: Use `~/.archon/.env` as the single source of truth:

```bash
# Create global config
mkdir -p ~/.archon
cp .env.example ~/.archon/.env
# Edit with your values

# For server, symlink to repo
ln -s ~/.archon/.env .env
```

## Docker Configuration
Expand Down
9 changes: 5 additions & 4 deletions packages/docs-web/src/content/docs/reference/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,14 @@ The GitHub and Gitea adapters verify webhook signatures to ensure payloads origi
- The `.env.example` file in the repository contains placeholder values -- copy it and fill in real values.
- Never commit `.env` files to git. The repository's `.gitignore` excludes them.

**CWD `.env` isolation:**
- When running inside a target repository, Bun auto-loads that repo's `.env` before any Archon code runs. Both the CLI and server strip every key parsed from the CWD `.env` at startup, then load only `~/.archon/.env` (which always wins via `override: true`). This prevents target-repo secrets (e.g. `ANTHROPIC_API_KEY`, `DATABASE_URL`, `OPENAI_API_KEY`) from bleeding into Archon or its subprocesses.
- Claude Code subprocesses receive only an explicit allowlist of env vars (system essentials, Claude auth, Archon runtime config, git identity, GitHub tokens). Per-codebase env vars configured via `codebase_env_vars` or `.archon/config.yaml` `env:` are merged on top of this filtered base.
**Subprocess env isolation:**
- Bun auto-loads `.env` from CWD before any Archon code runs. These vars remain in the server/CLI's `process.env` but **cannot reach AI subprocesses** — Claude Code subprocesses receive only an explicit allowlist of env vars (`SUBPROCESS_ENV_ALLOWLIST`: system essentials, Claude auth, Archon runtime config, git identity, GitHub tokens). Keys like `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and `DATABASE_URL` are not on the allowlist and are blocked.
- `~/.archon/.env` is loaded with `override: true`, so Archon's own config always wins over any Bun-auto-loaded CWD vars for overlapping keys.
- Per-codebase env vars configured via `codebase_env_vars` or `.archon/config.yaml` `env:` are merged on top of this filtered base at workflow execution time.

### Env-leak gate (target repo `.env` keys)

Archon scrubs its own environment, but **Bun auto-loads `.env` from the subprocess working directory** before any user code runs. That means a Claude or Codex subprocess started with `cwd=/path/to/target/repo` will re-inject any sensitive keys present in that repo's auto-loaded `.env` files — bypassing the allowlist above and silently billing the wrong API account.
Beyond the subprocess allowlist, Archon also scans target repos for sensitive keys **before spawning**. A Claude or Codex subprocess started with `cwd=/path/to/target/repo` inherits its own Bun auto-loaded `.env` the env-leak gate catches this by scanning the target repo's `.env` files at registration and pre-spawn time.

**What Archon scans:** auto-loaded filenames `.env`, `.env.local`, `.env.development`, `.env.production`, `.env.development.local`, `.env.production.local`.

Expand Down
19 changes: 19 additions & 0 deletions packages/docs-web/src/styles/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,22 @@
--sl-font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--sl-font-mono: 'JetBrains Mono', ui-monospace, monospace;
}

[data-theme='dark'] {
--sl-color-bg: #0f1219;
--sl-color-bg-sidebar: #131825;
--sl-color-bg-nav: #0f1219;
--sl-color-hairline-light: #1e293b;
}

/* !important needed: Starlight sets .hero padding/gap via inline styles */
.hero {
padding-block: 2rem !important;
gap: 1rem !important;
}

/* .sidebar-content is an internal Starlight class (not a public API) — re-test after Starlight upgrades */
[data-theme='dark'] .sidebar-content a[aria-current='page'] {
background: linear-gradient(135deg, rgba(168, 85, 247, 0.15), rgba(59, 130, 246, 0.15));
border-left-color: #a855f7;
}
2 changes: 1 addition & 1 deletion packages/git/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/git",
"version": "0.1.0",
"version": "0.3.4",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/isolation/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/isolation",
"version": "0.1.0",
"version": "0.3.4",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/paths/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/paths",
"version": "0.2.0",
"version": "0.3.4",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@archon/server",
"version": "0.2.0",
"version": "0.3.4",
"type": "module",
"main": "./src/index.ts",
"scripts": {
Expand Down
Loading
Loading