Skip to main content

Command Scopes

The global command set G is partitioned into three disjoint scopes:

G = G_core ∪ G_alias ∪ G_p

This partition is an invariant of the system: a command belongs to exactly one scope, enforced at registration time.


G_core — Core Commands

Definition: Global commands available in all contexts, with no protocol dependency.

TypeScript tag: scope: 'G_core'

Implementation: src/core/commands.ts

Commands:

CommandDescription
helpFiber-aware command listing — shows current fiber's commands + essential globals
use <protocol>Enter a protocol fiber (sets activeProtocol)
exitExit current protocol fiber (clears activeProtocol)
historyShow command execution log from ExecutionContext
walletShow wallet connection status
whoamiDisplay connected address
balanceShow wallet token balance
price <symbol>Get token price (routes to 1inch or CoinPaprika via --protocol flag)
chart <type>Add chart to analytics panel
clearClear terminal output

Key property: G_core commands are always available regardless of which fiber is active. When inside a protocol fiber, help shows the fiber's commands plus an "essential globals" subset (help, exit, clear, history, wallet, whoami, balance).


G_alias — Aliased Commands

Definition: Protocol-agnostic commands that bind to a protocol fiber at runtime based on active context or user preferences.

TypeScript tag: scope: 'G_alias'

Status: Planned — not yet implemented. Requires 2+ protocols implementing the same function (e.g., two DEX protocols both implementing swap).

Deferred to: v2.0

Example (future):

# When both Uniswap and 1inch are available, 'swap' is a G_alias
# It resolves to the active protocol's swap command:
user@uniswap> swap 10 usdc eth # → uniswap:swap
user@1inch> swap 10 usdc eth # → 1inch:swap
user@defi> swap 10 usdc eth # → resolves by preference/default

Open question: Default protocol ordering for alias resolution (user preference vs chain context). See Internal: Roadmap.


G_p — Protocol-Specific Commands

Definition: Commands bound to a specific protocol P. Together, all G_p commands for protocol P form the protocol fiber M_P.

TypeScript tag: scope: 'G_p', protocol: '<protocol-id>'

Implementation: src/plugins/[protocol]/commands.ts

Examples:

CommandProtocolNamespace form
swap1inch1inch:swap
quote1inch1inch:quote
bridgelifilifi:bridge
routeslifilifi:routes
bridgewormholewormhole:bridge
quotewormholewormhole:quote
bridgestargatestargate:bridge
cpricecoinpaprikacoinpaprika:cprice
coinsearchcoinpaprikacoinpaprika:coinsearch
cchartcoinpaprikacoinpaprika:cchart

Resolution: G_p commands are resolved in priority order:

  1. Explicit --protocol flag
  2. Namespaced form (protocol:command)
  3. Active protocol context (set via use)
  4. User preferences

Partition Invariant

The three scopes are mutually exclusive. The invariant is:

G_core ∩ G_alias = ∅
G_core ∩ G_p = ∅
G_alias ∩ G_p = ∅

This is enforced programmatically:

  • G_core commands are registered via registerCoreCommands() into the coreCommands map.
  • G_alias commands would be registered into the aliasedCommands map (future).
  • G_p commands are registered via addCommandToFiber(), which validates scope === 'G_p' and protocol === fiber.id before adding.

If a command attempts to register with the wrong scope, addCommandToFiber throws:

if (command.scope !== 'G_p') {
throw new Error(`Expected G_p scope, got ${command.scope}`)
}
if (command.protocol !== fiber.id) {
throw new Error(`Protocol mismatch: ${command.protocol} !== ${fiber.id}`)
}

Practical Implications

For users:

  • G_core commands work anywhere. You never lose access to help, exit, wallet, etc.
  • To access protocol commands without entering the fiber, use namespace syntax: 1inch:swap.
  • When inside a fiber, unqualified commands resolve to that fiber's commands first.

For plugin authors:

  • Every command in your plugin must use scope: 'G_p' and protocol: '<your-id>'.
  • Never use scope: 'G_core' in a plugin command — it will either throw (if passed to addCommandToFiber) or pollute the global namespace (if imported directly into core commands).
  • The protocol ID in your command must match your plugin's metadata.id exactly.

See Guides: Add a Command for the full workflow.