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
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,56 @@ node dist/index.js new_chat

### 6. send_prompt

Sends a natural language prompt to CoinFello. If the server requires a delegation to execute the action, the CLI creates and signs a subdelegation automatically based on the server's requested scope and chain. Requires `create_account` and `sign_in` to have been run first.
Sends a natural language prompt to CoinFello. If the server requires a delegation to execute the action, the CLI saves the delegation request to a local file and logs the details to the terminal. The delegation is **not** signed or submitted automatically — you must explicitly approve it with `approve_delegation_request`. Requires `create_account` and `sign_in` to have been run first.

```bash
node dist/index.js send_prompt "send 5 USDC to 0xRecipient..."
```

Expected output:
Expected output (when delegation is requested):

```
Sending prompt...
Delegation requested: scope=erc20, chainId=8453
=== Delegation Request ===
Scope type: erc20TransferAmount
Chain ID: 8453
Token address: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Max amount: 5000000
Original prompt: "send 5 USDC to 0xRecipient..."
Justification: "Transfer 5 USDC to 0xRecipient on Base"
Requested at: 2026-03-16T12:34:56.789Z
Chat ID: chat_abc123
Call ID: call_abc123
==========================
Delegation request saved to: /home/<user>/.clawdbot/skills/coinfello/pending_delegation.json
Run 'approve_delegation_request' to sign and submit this delegation.
```

### 7. approve_delegation_request

Approves and signs a pending delegation request saved by `send_prompt`, then submits it to CoinFello.

```bash
node dist/index.js approve_delegation_request
```

Expected output:

```
Approving delegation request...
=== Delegation Request ===
...
==========================
Fetching CoinFello delegate address...
Loading smart account...
Creating subdelegation...
Signing subdelegation...
Sending signed delegation...
Transaction submitted successfully.
Transaction ID: <txn_hash_>
Transaction ID: <txn_hash>
```

### 7. signer-daemon
### 8. signer-daemon

Manages the Secure Enclave signing daemon. Without the daemon, each signing operation (account creation, sign-in, delegation signing) triggers a separate Touch ID / password prompt. Starting the daemon authenticates once and caches the authorization for subsequent operations.

Expand Down
41 changes: 31 additions & 10 deletions coinfello/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ This skill performs the following sensitive operations:
- **Key generation and storage**: By default, `create_account` generates a hardware-backed P256 key in the **macOS Secure Enclave** (or TPM 2.0 where available). The private key never leaves the hardware and cannot be exported — only public key coordinates and a key tag are saved to `~/.clawdbot/skills/coinfello/config.json`. If hardware key support is not available, the CLI warns and falls back to a software private key. You can also explicitly opt into a plaintext software key by passing `--use-unsafe-private-key`, which stores a raw private key in the config file — **this is intended only for development and testing**.
- **Signer daemon**: Running `signer-daemon start` authenticates once via Touch ID / password and caches the authorization. All subsequent signing operations reuse this cached context, eliminating repeated auth prompts. The daemon communicates over a user-scoped Unix domain socket with restricted permissions (`0600`). If the daemon is not running, signing operations fall back to direct execution (prompting Touch ID each time).
- **Session token storage**: Running `sign_in` stores a SIWE session token in the same config file.
- **Delegation signing**: Running `send_prompt` may automatically create and sign blockchain delegations based on server-requested scopes, then submit them to the CoinFello API.
- **Delegation signing**: Running `send_prompt` may receive a delegation request from the server, which is saved to a local file. Running `approve_delegation_request` creates and signs the delegation, then submits it to the CoinFello API.

Users should ensure they trust the CoinFello API endpoint configured via `COINFELLO_BASE_URL` before running delegation flows.

Expand All @@ -70,8 +70,11 @@ npx @coinfello/agent-cli@latest create_account
# 3. Sign in to CoinFello with your smart account (SIWE)
npx @coinfello/agent-cli@latest sign_in

# 4. Send a natural language prompt — the server will request a delegation if needed
# 4. Send a natural language prompt — if a delegation is needed, it will be saved for review
npx @coinfello/agent-cli@latest send_prompt "send 5 USDC to 0xRecipient..."

# 5. Approve the delegation request (if one was saved by send_prompt)
npx @coinfello/agent-cli@latest approve_delegation_request
```

## Commands
Expand Down Expand Up @@ -148,7 +151,7 @@ npx @coinfello/agent-cli@latest signer-daemon stop # Stop the daemon

### send_prompt

Sends a natural language prompt to CoinFello. If the server requires a delegation to execute the action, the CLI creates and signs a subdelegation automatically based on the server's requested scope and chain.
Sends a natural language prompt to CoinFello. If the server requires a delegation to execute the action, the CLI saves the delegation request to a local file and logs the details to the terminal for review. The delegation is **not** signed automatically — you must explicitly approve it with `approve_delegation_request`.

```bash
npx @coinfello/agent-cli@latest send_prompt "<prompt>"
Expand All @@ -164,12 +167,27 @@ then you should call `npx @coinfello/agent-cli@latest new_chat` to start a new c
2. If the server returns a read-only response (no `clientToolCalls` and no `txn_id`) → prints the response text and exits
3. If the server returns a `txn_id` directly with no tool calls → prints it and exits
4. If the server sends an `ask_for_delegation` client tool call with a `chainId` and `scope`:
- Fetches CoinFello's delegate address
- Rebuilds the smart account using the chain ID from the tool call
- Parses the server-provided scope (supports ERC-20, native token, ERC-721, and function call scopes)
- Creates and signs a subdelegation (wraps with ERC-6492 signature if the smart account is not yet deployed on-chain)
- Sends the signed delegation back as a `clientToolCallResponse` along with the `chatId` and `callId` from the initial response
- Returns a `txn_id` for tracking
- Saves the delegation request (scope, chain ID, call ID, chat ID) to `~/.clawdbot/skills/coinfello/pending_delegation.json`
- Logs a human-readable summary of the delegation request to the terminal
- Exits without signing — run `approve_delegation_request` to approve

### approve_delegation_request

Approves and signs a pending delegation request saved by `send_prompt`, then submits it to CoinFello.

```bash
npx @coinfello/agent-cli@latest approve_delegation_request
```

**What happens internally:**

1. Reads the pending delegation from `~/.clawdbot/skills/coinfello/pending_delegation.json`
2. Fetches CoinFello's delegate address
3. Rebuilds the smart account using the chain ID from the delegation request
4. Parses the scope and creates a subdelegation (wraps with ERC-6492 signature if the smart account is not yet deployed on-chain)
5. Sends the signed delegation back as a `clientToolCallResponse` along with the `chatId` and `callId`
6. Clears the pending delegation file
7. Returns a `txn_id` for tracking

## Common Workflows

Expand All @@ -185,8 +203,11 @@ npx @coinfello/agent-cli@latest create_account
# Sign in (required for delegation flows)
npx @coinfello/agent-cli@latest sign_in

# Send a natural language prompt — delegation is handled automatically
# Send a natural language prompt — if a delegation is needed, it will be saved for review
npx @coinfello/agent-cli@latest send_prompt "send 5 USDC to 0xRecipient..."

# Review the delegation request logged to the terminal, then approve it
npx @coinfello/agent-cli@latest approve_delegation_request
```

### Read-Only Prompt
Expand Down
53 changes: 49 additions & 4 deletions coinfello/references/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,40 @@ Created automatically by `create_account`. The schema depends on the signer type
| `delegation` | `object` | `set_delegation` | Optional stored delegation |
| `chat_id` | `string` | `send_prompt` | Persisted conversation chat ID reused across prompts; removed by `new_chat` |

## Pending Delegation File

Location: `~/.clawdbot/skills/coinfello/pending_delegation.json`

Created by `send_prompt` when the server requests a delegation. Read and cleared by `approve_delegation_request`.

```json
{
"delegationArgs": {
"chainId": 8453,
"scope": {
"type": "erc20TransferAmount",
"tokenAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"maxAmount": "5000000"
},
"justification": "Transfer 5 USDC to 0xRecipient on Base"
},
"callId": "call_abc123",
"chatId": "chat_xyz789",
"originalPrompt": "send 5 USDC to 0xRecipient...",
"createdAt": "2026-03-16T12:34:56.789Z",
"description": "Delegation for scope=erc20TransferAmount, chainId=8453"
}
```

| Field | Type | Description |
| ---------------- | -------- | ------------------------------------------------------------------------- |
| `delegationArgs` | `object` | Tool call arguments from the server (chainId, scope, justification, etc.) |
| `callId` | `string` | Tool call ID from the `ask_for_delegation` response |
| `chatId` | `string` | Chat session ID for conversation continuity |
| `originalPrompt` | `string` | The prompt that triggered the delegation request |
| `createdAt` | `string` | ISO-8601 timestamp of when the request was received |
| `description` | `string` | Human-readable summary of the delegation request |

## Command Reference

### npx @coinfello/agent-cli@latest create_account
Expand Down Expand Up @@ -131,10 +165,20 @@ npx @coinfello/agent-cli@latest send_prompt <prompt>
| --------- | -------- | -------- | ------- | -------------------------------------------- |
| `prompt` | `string` | Yes | — | Natural language prompt to send to CoinFello |

The server determines whether a delegation is needed and, if so, what scope and chain to use. The client creates and signs the subdelegation based on the server's `ask_for_delegation` client tool call response. Each subdelegation is created with a unique random salt to ensure delegation uniqueness.
The server determines whether a delegation is needed and, if so, what scope and chain to use. If the server responds with an `ask_for_delegation` tool call, the delegation request is saved to `~/.clawdbot/skills/coinfello/pending_delegation.json` and logged to the terminal. The delegation is **not** signed automatically — run `approve_delegation_request` to approve it.

`send_prompt` reuses `chat_id` from config when available and persists server-returned `chatId` values for continued context across calls.

### npx @coinfello/agent-cli@latest approve_delegation_request

```
npx @coinfello/agent-cli@latest approve_delegation_request
```

No parameters. Reads the pending delegation request from `~/.clawdbot/skills/coinfello/pending_delegation.json`, creates and signs a subdelegation, and submits it to CoinFello. Clears the pending delegation file on success.

Each subdelegation is created with a unique random salt to ensure delegation uniqueness.

**ERC-6492 signature wrapping**: If the smart account has not yet been deployed on-chain, the CLI wraps the delegation signature using ERC-6492 (`serializeErc6492Signature`) with the account's factory address and factory data. This allows the delegation to be verified even before the account contract exists.

## Supported Chains
Expand Down Expand Up @@ -177,7 +221,7 @@ The `send_prompt` command fetches this list and uses the first agent's `id` as `

### POST /api/conversation body

Initial request (prompt only):
Initial request (prompt only, sent by `send_prompt`):

```json
{
Expand All @@ -189,7 +233,7 @@ Initial request (prompt only):

`agentId` is dynamically resolved from the `/api/v1/automation/coinfello-agents` endpoint (not hardcoded).

The follow-up request (sending the signed delegation back) is handled internally by `send_prompt` — no manual construction is needed.
The follow-up request (sending the signed delegation back) is handled internally by `approve_delegation_request` — no manual construction is needed.

### POST /api/conversation response

Expand Down Expand Up @@ -278,7 +322,7 @@ All `amount` fields are in the token's smallest unit (e.g. `5000000` for 5 USDC
- **Key generation and storage**: By default, `create_account` generates a hardware-backed P256 key in the **macOS Secure Enclave**. The private key never leaves the hardware and cannot be exported — only public key coordinates and a key tag are saved to `~/.clawdbot/skills/coinfello/config.json`. A plaintext private key is **only** stored when `--use-unsafe-private-key` is explicitly passed (intended for development/testing). Restrict file permissions (e.g. `chmod 600`) and do not share or commit this file.
- **Signer daemon**: The daemon caches a single authenticated `LAContext` on startup, so all signing operations within the session reuse the same authorization. The Unix domain socket is created with `0600` permissions and scoped to the current OS user. The daemon cleans up socket and PID files on `SIGTERM`/`SIGINT`.
- **Session token storage**: `sign_in` stores a SIWE session token in the same config file.
- **Automatic delegation signing**: `send_prompt` may create and sign delegations based on scopes requested by the server, then submit them to the CoinFello API endpoint. Ensure the `COINFELLO_BASE_URL` points to a trusted endpoint before running delegation flows.
- **Delegation signing**: `send_prompt` saves delegation requests from the server to a local file. `approve_delegation_request` creates and signs the delegation, then submits it to the CoinFello API endpoint. Ensure the `COINFELLO_BASE_URL` points to a trusted endpoint before approving delegation requests.

## Error Messages

Expand All @@ -288,5 +332,6 @@ All `amount` fields are in the token's smallest unit (e.g. `5000000` for 5 USDC
| `Secure Enclave config missing. Run 'create_account' first.` | Missing Secure Enclave key data | Run `npx @coinfello/agent-cli@latest create_account` |
| `No smart account found. Run 'create_account' first.` | Missing smart account in config | Run `npx @coinfello/agent-cli@latest create_account` |
| `No delegation request received from the server.` | Server returned unexpected response | Check the full response JSON printed |
| `No pending delegation request found.` | No delegation saved by `send_prompt` | Run `send_prompt` first to generate a request |
| `Signing daemon is already running.` | Daemon already started | Use `signer-daemon status` to confirm |
| `Signing daemon is not running.` | Daemon not started or already stopped | Run `signer-daemon start` |
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coinfello/agent-cli",
"version": "0.2.2",
"version": "0.3.0",
"description": "CLI for managing a web3 smart account and executing blockchain transactions via CoinFello",
"repository": "CoinFello/agent-cli",
"homepage": "https://coinfello.com",
Expand Down
2 changes: 1 addition & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface Config {
}
}

const CONFIG_DIR = join(homedir(), '.clawdbot', 'skills', 'coinfello')
export const CONFIG_DIR = join(homedir(), '.clawdbot', 'skills', 'coinfello')
export const CONFIG_PATH = join(CONFIG_DIR, 'config.json')

export async function loadConfig(): Promise<Config> {
Expand Down
Loading
Loading