Skip to content

Trading

There are two ways to trade: ask your agent, or type the trade yourself. Either way, a live trade is a card you approve with one key press, unless you’ve let its wallet trade inside limits.

  • Paper trades are recorded at the quoted price and never sent. They need no funds and no card. The Candle Harness starts on paper.
  • Live trades move real funds.

Click PAPER or LIVE in the status bar, or type paper or live. Switching to live asks first, and the question lists what a first live trade would still be missing: a key that isn’t allowed a wallet yet (with a chip that types the line that allows it), no limits set here, or a wallet with no SOL. y still switches. The mode you last picked is kept across restarts.

Triggers and bots keep the mode you approved each with: switching here changes none of them, and the switch says how many triggers stay as approved (Triggers, Rules bots).

buy $10 of MOON

The agent proposes the trade, and it becomes a card in its pane. The agent can’t approve it.

A trade card waiting in the agent's pane, approved with one key press

A card is priced fresh when it’s proposed, from Candle’s market read, and checked against the agent’s limits there and then. A trade over a limit is refused, with the figures, and never becomes a card you could approve.

A trade card names its token and, dim beside it, the token’s short address; ctrl-o has the address in full. If the same name is held in one of your wallets, or was on an earlier card, for another token, the card says so in amber. The receipt of a trade that ran without a card shows the same.

Once a card waits, the agent’s turn ends there. It reads how the trade went the next time you message it.

KeyWhat it does
⏎, with the line emptyApproves the highlighted card, once it has shown for 300 ms. A card that arrives while another is open waits 1.5 seconds before ⏎ takes it, and the hint line says ”⏎ approves in a moment” until then, so a press meant for the card you were reading can’t land on a new one
a click on its ⏎ approve chipApproves it too. A click elsewhere on the card picks its token
ctrl-nRejects it
ctrl-oShows everything it’s bound to: the amounts, the price, the wallet that pays, the limits it was checked against, and the other wallets it could pay from
ctrl-rRe-quotes the newest expired card that can be re-quoted, at the current price

With two cards waiting, the one ⏎ approves is shaded. A card that isn’t approved expires, which is safe: nothing is sent. A trade, swap, launch or stake card can be re-quoted once expired. A card made from something that may have changed since (a trigger’s, a bot’s, a change to approvals or to Hacc, less access) can’t: it says “expired, never ran: ask for it again”. Candle fills at its own price, within its slippage limit. That’s 1% unless the agent sets another (0.5% from a TEE wallet, the CLI’s default). When it does, the card says so (“slippage 5%, the default is 1%”), in amber when it’s looser, and so does the receipt of a trade that ran without a card. On a wallet that trades inside limits, a looser bound makes the trade a card, a sell included.

The card says which wallet pays, and how each card was approved is recorded in the Journal: by ⏎, by a click, or without a card.

Type a trade in full on the input line:

buy 0.1 sol MOON
buy $25 MOON
sell 50% MOON
sell 1000 MOON
swap 0.1 SOL USDC
  • Amounts: an amount of SOL, USDC or CNDL; a dollar amount, converted when the card is made into SOL (or the asset in trade.spendAsset); a percent of what you hold, from 1% to 100%; or an amount of the token.
  • Swaps are between base assets: SOL, USDC, CNDL, ETH or USDG. SOL, USDC, ETH and USDG can’t be the token of a buy or sell, live or on paper: convert one with a swap.
  • The token is its mint, or a name a pane or the agent has shown this session. A name nobody has shown is never guessed: the Candle Harness says so and offers ctrl-t to ask the agent which token you mean. SOL, USDC, ETH, USDG and CNDL only ever mean the real assets, never a token that calls itself by one of those names.
  • A line shaped like a trade that can’t run says why, keeps the line for you to fix, and sends nothing. It never quietly becomes a message to the agent.

A typed live trade is a card by default, so you see its price before it goes. With [cards] typedTrades = "instant" in config.toml, a trade you type runs at once, inside the agent’s limits.

… as agent-b runs the line as another agent, and … from <wallet> names the wallet that pays: buy $25 MOON from embedded. Wallets says how a wallet is picked.

Now and then Candle doesn’t answer a trade in time. The Candle Harness reads it back from Candle under the same id before doing anything else, so a trade is never sent twice. If it still can’t tell, the trade waits in the agent pane:

  • resend sends it again, after reading it back first. Only the main window can;
  • abandon lets it go.

Or click the trade in the agent pane.

A swap whose first leg went and whose second failed says “part done”, never plainly failed, and its first leg counts toward the day.

A bridge (SOL or USDC to ETH or USDG, or back) rarely fills in the seconds the swap is measured in, so its settlement usually first reads pending. To learn how it settled, the agent reads it again with candle_get_swap_receipt, by the swap’s clientSwapId or any of its hashes, no more than once every 15 seconds. That read moves nothing and never resends the swap. A failed bridge says whether Relay refunded it (bridgeStatus: "refund").

An alias stands for the start of a line. Put them in config.toml:

[aliases]
b5 = "buy $5 of"
s = "sell 100% of"

Then b5 MOON buys $5 of MOON. An alias can’t take a built-in name such as buy, can’t loop, and can’t run more than 5 parts. One that’s left out is named with its line, when the Candle Harness starts and in candle-harness doctor. The palette’s alias rows reload the file.

A ; chains up to 5 trades or candle commands:

buy $1 of MOON; sell 100% of MOON
  • Every part is checked before anything is sent. A part that would be refused refuses the whole line, naming its number.
  • Then the parts run one after another: each is sent only once the one before has ended. So the sell above is sized from what the buy left you.
  • A part that’s rejected, fails or isn’t answered stops the rest, and the message says what was sent.
  • A line is a chain only when its first part is a command, so a message to the agent with a semicolon in it still goes to the agent.

candle <command> runs any of Candle’s CLI commands under its rule:

  • a read runs at once, and you see the output;
  • one that only takes access away (revoking a key, say) runs at once when you type it;
  • one that spends or changes something is a card;
  • an owner step, or one that asks for a passphrase or shows a secret, runs in the prompt pane.

The agent runs them the same way when you ask it. Candle’s commands in the Candle Harness lists every command with its rule.

A launch, a stake or unstake, a fee or staking-reward claim, a profile edit, a post, an image upload and a token’s description and links (edited by the account that launched it) are one-press cards, like a trade’s. They’re live only.

  • A launch, a stake and a fee claim are dry-run first, and the card shows the preview. A dry run Candle refuses makes no card.
  • A launch’s first buy is valued and limited like a buy.
  • A launch card shows what the press publishes besides the name: its description, the sites its links and images point to, and, in amber, any terms that aren’t Candle’s defaults.
  • A card for one of Candle’s tools is refused if it carries an argument the Candle Harness doesn’t know, so nothing unshown rides on a press.
  • A public action (a post, a profile edit, an upload, a token edit) says so on the card. An image upload says it’s public and permanent.
  • A launch image goes by its URL. To use a file, upload it first with image upload, from the agent’s research folder.

On Candle, but not in the Candle Harness yet

Section titled “On Candle, but not in the Candle Harness yet”
  • Limit and stop orders held by Candle. Candle offers them on Max (Limit and bracket orders). In the Candle Harness, a stop or a take profit is a trigger or a bot’s exit, watched on this machine.
  • Telegram alerts. Set them up on Candle (Alerts).
  • Perps trading. The Perps tab shows what works for perps today, and what to ask the agent. The tabs has it.
  • Writing to a token’s page. Claiming a page, writing its sections, holder updates and comments need a key with token-pages access, which no agent key in the Candle Harness has. Reading a page works. Run the writes with candle token in your own terminal, with a key made for it.
  • Pricing. [pricing] in config.toml sets where a card’s price comes from. A card is never re-priced on approve.
  • Trading inside limits. A wallet can run small trades with no card, leaving a receipt instead. Limits explains it.

If a leg’s receipt is not confirmed the Harness says the leg “may have been broadcast” and does not repeat the trade. Run the status command it names (for a Hood trade, --kind trade); it reads the exact transaction and sends nothing. “No leg is confirmed yet” means no receipt has been seen, not that nothing was sent. A reverted leg says so and notes that network fees may have been charged.

Legacy Hood leg recovery and readable guards

Section titled “Legacy Hood leg recovery and readable guards”

A WALLET_BUSY refusal names the guarded operationId, rail (operationKind), client refId, leg, fixed reason, clearingCondition, statusPath and statusCommand. An operation id is separate from a rail’s client id:

Terminal window
candle swap status --operation <operationId>
candle swap recover --operation <operationId> --hash <0x-transaction-hash>

GET /api/v1/agent/hood-tee/operations/{operationId} and POST /api/v1/agent/hood-tee/operations/{operationId}/recover return { success: true, operation: { ..., guard?, recovery? } }. The POST body accepts only { candidateHash?: string }. A locator names a transaction to verify; it never proves identity. Both paths use the account’s owning rail scope (swap:write, launch:read, or transfer:write); swap operations also require the key that placed them. An unauthorized lookup returns the same 404 JOB_NOT_FOUND as an unknown id. Recovery inside an active window returns 409 OPERATION_ACTIVE, retryable true. Reads and recovery work while the trading switch is off.

Legacy recovery reconstructs the exact signed type-2 envelope and verifies its hash, signer and historical Candle stamp before recording an exact-hash receipt. It needs no client-held bytes. It never signs, sends, rebroadcasts, restamps, returns a next leg, collects fees or revives the operation. Failed/expired parents and unattempted planned legs keep their labels. Proving one leg keeps every other unresolved leg held. A nonce count, elapsed time, missing transaction, allowance or terminal job label cannot clear a hold. not_sent requires positive bound claim proof that signing cannot have happened or happen later; pending/ambiguous claims remain held.

While guard.recoveryRequired is true, read status and follow clearingCondition. CLI status and recover exit 3 while held. legacy_identity_missing can accept a locator; nonce_conflict, receipt_conflict, legacy_candidate_conflict and legacy_proof_incomplete keep the wallet held until the stated proof or a separately reviewed disposition exists. A landed leg stays landed. No rebuild or repeat-trade instruction follows an uncertain result.

Every Hood rail job read carries its operation’s guard, regardless of the job’s terminal label. GET /api/v1/agent/wallets/{walletId}/hood-tee is the read-only locator of last resort, even with no job row: guard: { held, incomplete, operations } lists at most 10 held operations. A held failed/expired operation also makes activeOperation non-null for installed custody clients. Incomplete proof without a known holder omits activeOperation, so those clients fail closed. Current custody commands refuse WALLET_GUARDED. Preserve that compatibility projection during rollback. This endpoint performs no recovery writes.

SDK: getHoodTeeOperation(operationId) and recoverHoodTeeOperation(operationId, { candidateHash? }); GuardSummary and WalletBusyDetails are exported. MCP: candle_get_operation accepts operationId exclusively instead of clientId/kind; candle_recover_operation accepts operationId and optional candidateHash. An older API without explicit operation lookup requires reading the job by its client id. These client source changes require a separate human package release; this repair bumps no version.