-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Why
AI coding assistants (Claude Code, Cursor, GitHub Copilot, Codex) auto-load project context files when opening a repository — CLAUDE.md, AGENTS.md, .cursorrules, etc. Without these files, AI tools start with zero project context: they don't know about furious-commander patterns, the RootCommand base class, how config loading works, domain concepts like stamps and feeds, or how to run tests.
Adding these files means:
- Faster onboarding — AI understands the architecture before generating code
- Fewer mistakes — knows about
Optional<T>, verbosity levels, config priority, decorator patterns - Consistent output — follows existing code style (no semicolons, conventional commits, Prettier settings)
Proposed CLAUDE.md
Full file content (click to expand)
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Swarm CLI (`@ethersphere/swarm-cli`) is a TypeScript command-line tool for interacting with Bee nodes on the Ethereum Swarm network. It wraps the Bee HTTP API via `@ethersphere/bee-js` and provides commands for uploads, downloads, postage stamps, feeds, identities, PSS messaging, manifests, pinning, staking, and more.
**Key dependencies:**
- **CLI framework**: `furious-commander` (decorator-based command/option parsing)
- **Swarm client**: `@ethersphere/bee-js`
- **Crypto**: `@ethereumjs/wallet`, `ethers`
- **UX**: `chalk`, `ora`, `cli-progress`, `inquirer`
## Build & Development Commands
```bash
npm install # Install dependencies
npm run build # Compile TypeScript (rimraf dist && tsc)
npm start # Run via ts-node (development)
npm test # Run Jest test suite (requires 5 live Bee nodes)
npm run check # Type-check without emitting (includes test files)
npm run lint # ESLint + Prettier (auto-fix)
npm run lint:check # Lint without fixing
npm run bee # Start local Bee cluster via fdp-play (5 nodes)
```
Requires **Node >= 14** (18+ recommended). TypeScript target is ES2020, module system is CommonJS.
## Architecture
### furious-commander Framework
All commands use the `furious-commander` library which provides:
- **`LeafCommand`** — a terminal command that executes logic (`async run()`)
- **`GroupCommand`** — a namespace that holds subcommands
- **Decorators**: `@Argument`, `@Option`, `@ExternalOption` for declarative CLI parsing
- **Entry point**: `cli()` function called from `src/index.ts`
### Command Hierarchy
Commands are registered in `src/config.ts` via `rootCommandClasses`. There are 17 root commands:
| Leaf Commands | Group Commands (with subcommands) |
|---------------|-----------------------------------|
| Upload, Download, Hash, Status, Addresses, Quickstart | Stamp (Buy, Create, Dilute, Extend, List, Show, Topup) |
| | Identity (Create, Export, Import, List, Remove, Rename, Show) |
| | Feed (Print, Update, Upload) |
| | Cheque (Cashout, Deposit, List, Withdraw, WithdrawAll) |
| | Pinning (Remove, Show, Update) |
| | PSS (Receive, Send, Subscribe) |
| | Manifest (Add, Download, List, Remove, Show, Update) |
| | Stake (Show, Deposit, Withdraw, WithdrawAll) |
| | Wallet, Utility, Grantee (Create, Get, Patch) |
### RootCommand Base Class
Every command extends `RootCommand` (`src/command/root-command/index.ts`), which provides:
- **`this.bee`** — `Bee` or `BeeDev` client instance (based on `--dev` flag)
- **`this.console`** — `CommandLog` with verbosity-aware logging
- **`this.commandConfig`** — `CommandConfig` for reading/writing `~/.swarm-cli/config.json`
- **`this.result`** — `Optional<Reference>` for the command's output reference (used in tests)
The `protected init()` method runs automatically and:
1. Loads config file (creates default if missing)
2. Merges config values where CLI/env weren't explicitly set (via `Sourcemap`)
3. Creates the `Bee` client with configured URL and options
4. Sets verbosity level from `--quiet` / `--verbose` flags
### Command Authoring Pattern
```typescript
// Leaf command example
export class Upload extends RootCommand implements LeafCommand {
public readonly name = 'upload'
public readonly alias = 'up'
public readonly description = 'Upload file to Swarm'
@Argument({ key: 'path', description: '...', required: true, autocompletePath: true })
public path!: string
@Option(stampProperties)
public stamp!: string
@Option({ key: 'encrypt', type: 'boolean' })
public encrypt!: boolean
async run(): Promise<void> {
await super.init() // Initialize bee, console, config
// Command logic using this.bee, this.console
}
}
// Group command example
export class Stamp implements GroupCommand {
public readonly name = 'stamp'
public readonly description = 'Buy, list and show postage stamps'
public subCommandClasses = [List, Create, Extend, Buy, Show, Dilute, Topup]
}
```
Some groups have a shared base class (e.g., `StampCommand`, `IdentityCommand`) that extends `RootCommand` with domain-specific helpers.
## Configuration System
**Priority** (highest to lowest):
1. CLI flag (e.g., `--bee-api-url http://...`)
2. Environment variable (`BEE_API_URL` or `SWARM_CLI_*`)
3. Config file value
4. Default
**Config file location:**
- Unix/macOS: `~/.swarm-cli/config.json`
- Windows: `%USERPROFILE%\AppData\swarm-cli\config.json`
- Override via `SWARM_CLI_CONFIG_FOLDER` / `SWARM_CLI_CONFIG_FILE` env vars
- File permissions: `0o600` (owner read/write only)
**Stored values:** `beeApiUrl` and `identities` (private keys / V3 keystores).
**Environment variables:**
- `BEE_API_URL` — Bee API endpoint (default: `http://localhost:1633`)
- `SWARM_CLI_CONFIG_FOLDER` — Custom config directory
- `SWARM_CLI_CONFIG_FILE` — Custom config filename (default: `config.json`)
## Global CLI Options
Defined in `src/config.ts`:
- `--bee-api-url` — Bee API endpoint
- `--verbose` / `-v` — Show all messages including dim/debug output
- `--quiet` / `-q` — Machine-readable output (only results and errors)
- `--curl` — Print equivalent curl commands for debugging
- `--header` / `-H` — Add custom HTTP headers to all requests
- `--yes` / `-y` — Skip interactive confirmation prompts
- `--dev` — Use `BeeDev` client (for dev-mode Bee nodes)
## Verbosity Levels
`CommandLog` (`src/command/root-command/command-log.ts`) has three modes:
| Level | Flag | Behavior |
|-------|------|----------|
| Quiet | `--quiet` | Only `error()`, `quiet()`, `all()` produce output |
| Normal | (default) | Adds `log()`, `info()`, `divider()` |
| Verbose | `--verbose` | Adds `verbose()`, `dim()` |
Use `this.console.log()` for normal output, `this.console.quiet()` for machine-parseable results, `this.console.verbose()` for debug details.
## Testing
**Framework**: Jest with `ts-jest`, configured in `jest.config.ts`.
**Pre-test setup** (runs in `jest.config.ts` before tests start):
- Spins up / waits for 5 Bee nodes on ports 1633, 11633, 21633, 31633, 41633
- Verifies all chequebook balances are 10 xBZZ
- Obtains a test postage stamp (`TEST_STAMP` env var)
- Gets worker PSS address (`WORKER_PSS_ADDRESS` env var)
**Start a local Bee cluster**: `npm run bee` (uses `fdp-play`)
**Test timeout**: 6 minutes (cryptographic operations are slow).
**Test utilities** (`test/utility/`):
- `invokeTestCli(argv)` — Programmatically invoke the CLI with arguments
- `describeCommand(description, fn)` — Test wrapper that captures console output, sets config folder, mocks `process.exit`
- Custom matchers: `toMatchLinesInOrder()`, `toMatchLinesInAnyOrder()`
**Test structure**: `test/command/` mirrors `src/command/`. Test data lives in `test/testpage/`, `test/data/`, `test/testconfig/`.
Set `SKIP_WORKER=1` to run a subset of tests that don't require worker nodes. Set `DEBUG=1` to see console output during tests.
## Domain Concepts
- **Postage stamps** — Prepaid storage tokens. Bought with BZZ, have a depth (capacity) and amount (duration). Commands: `stamp buy`, `stamp create`, `stamp list`, `stamp show`, `stamp topup`, `stamp dilute`, `stamp extend`.
- **Feeds** — Mutable references on immutable storage. An identity + topic produces a deterministic feed address. Commands: `feed print`, `feed update`, `feed upload`.
- **Identities** — Ethereum key pairs stored in config. Support simple wallets (raw private key) and V3 keystores (password-encrypted). Commands: `identity create`, `identity import`, `identity export`, `identity list`, `identity show`, `identity remove`, `identity rename`.
- **PSS (Postal Service over Swarm)** — Encrypted node-to-node messaging. Commands: `pss send`, `pss receive`, `pss subscribe`.
- **Manifests** — Trie-based directory structures mapping paths to content references. Commands: `manifest add`, `manifest remove`, `manifest list`, `manifest show`, `manifest download`, `manifest update`.
- **Pinning** — Mark content to prevent garbage collection. Commands: `pinning show`, `pinning update`, `pinning remove`.
- **Staking** — Lock BZZ for storage incentive participation. Commands: `stake deposit`, `stake withdraw`, `stake show`, `stake withdraw-all`.
- **Grantees (ACT)** — Access Control Trie for encrypted content sharing. Commands: `grantee create`, `grantee get`, `grantee patch`.
- **Cheques** — Payment channel settlements between nodes. Commands: `cheque list`, `cheque cashout`, `cheque deposit`, `cheque withdraw`, `cheque withdraw-all`.
## Common Pitfalls
- **Gateway vs full node** — Some commands need a full node (with `--dev` or a funded node). Gateway mode limits available API endpoints. Use `--dev` flag when connecting to a dev-mode Bee node.
- **`Optional<T>`** — Results use `Optional` from `cafe-utility`, not raw nulls. Check with `.isPresent()` / `.get()`.
- **Async spinners** — `ora` spinners are used for long-running operations. Don't mix direct `console.log` with spinner output; use `this.console.*` methods.
- **Stamp usability** — Not all stamps are usable (may be expired or depleted). The stamp picker filters these automatically.
- **Config file permissions** — Config is `0o600`. If permissions are wrong, the CLI may fail silently.
## Directory Map
```
src/
index.ts # Entry point — calls furious-commander cli()
config.ts # Root command registry and global option definitions
application.ts # App metadata (name, version)
command/
root-command/
index.ts # RootCommand base class
command-config.ts # Config file I/O, identity storage
command-log.ts # VerbosityLevel enum, CommandLog class
printer.ts # Low-level print functions
upload.ts, download.ts, ... # Leaf commands
stamp/, identity/, feed/, ... # Group command directories
service/
identity/ # Identity helpers (wallet loading, picking)
stamp/ # Stamp helpers (picking, printing)
utils/
error.ts # CommandLineError, errorHandler
option.ts # Shared option definitions (stampProperties, etc.)
spinner.ts # Ora spinner helpers
message.ts # User-facing message templates
text.ts # Text formatting (createKeyValue, etc.)
hex.ts, mime.ts, bzz-address.ts, contracts.ts, rpc.ts, chainsync.ts
test/
command/ # Integration tests (mirrors src/command/)
utility/ # Test helpers (invokeTestCli, describeCommand)
custom-matcher.ts # Jest custom matchers
testpage/, data/, testconfig/ # Test fixtures
```
## Code Style
- **No semicolons**, single quotes, trailing commas, 2-space indent, 120 char line width
- **Prettier** enforces formatting; **ESLint** enforces logic rules
- **Conventional commits** enforced by commitlint + husky
- **Strict TypeScript** with experimental decorators enabledAGENTS.md
We recommend also adding an AGENTS.md file with identical content. This filename is recognized by other AI coding tools (OpenAI Codex, Cursor, etc.), ensuring broad coverage regardless of which assistant a contributor uses. Maintaining two files with the same content is low-overhead since the content rarely changes.
Reference
Part of the effort tracked in ethersphere/DevRel#825 — adding AI context files to core Swarm repositories (bee, bee-js, swarm-cli).
Generated with AI