Singularity-Agent
Singularity-Agent — agentic blockchain, made practical

Read any blockchain from your terminal.

One tool for Ethereum, Solana, Bitcoin and Cosmos. Check what is in a wallet, look up what a transaction did, see what fees cost right now — and get the answer in the same shape no matter which chain it came from.

It never asks for your keys. Singularity can read the blockchain and prepare a payment for you, but it cannot sign or send one. There is no code in it that can move your money.

The idea

One tool instead of four

A blockchain is a public ledger. Anyone can read it — you do not need an account, a password, or anyone's permission. What you normally do need is the right tool for the right chain: one for Ethereum, a different one for Solana, another for Bitcoin. Each has its own address format, its own vocabulary, and its own way of telling you the same thing.

Singularity-Agent is one tool for all of them. You ask a question, it goes and reads the ledger, and it answers in a consistent format. A Bitcoin balance and a Cosmos balance come back with the same field names, so you only have to learn them once.

It works in two places: as a command you type in a terminal, and as a plugin for Claude, so you can ask questions in plain English instead. Both run exactly the same code.


Safety

What it can and can't do

Every crypto wallet is controlled by a private key — a long secret that acts like the password to your money. Anyone who has it can spend everything. The single most important thing to know about this tool is that it never touches yours.

It can read

  • Balances of any public address
  • What a past transaction did
  • Current network fees
  • Data stored in smart contracts
  • Prepare an unsigned payment for you

It cannot

  • Ask for, store, or read a private key
  • Sign a transaction
  • Send or broadcast anything
  • Move a single coin, in any circumstance
What "unsigned" means Singularity can fill out the paperwork for a payment — who is sending, who is receiving, how much, what it will cost. It hands that form to you. You sign it in your own wallet, where your key lives. Think of it as a very well-informed assistant who prepares the cheque but can never sign it.

The practical consequence: the worst thing a bug in this tool can do is give you a wrong answer. It cannot lose your funds, because it was never able to reach them.


Setup

Install it

This takes about two minutes. You'll be typing into a terminal — Terminal on macOS, PowerShell or Git Bash on Windows, or any shell on Linux.

  1. Install Node.js

    Singularity runs on Node.js version 20.10 or newer. Get it from nodejs.org if you don't have it, then check it worked:

    $ node --version
    v22.19.0

    Any number 20.10 or higher is fine.

  2. Download the code

    $ git clone https://github.com/DarkStarMatters/Singularity-Agent.git && cd Singularity-Agent
    Cloning into 'Singularity-Agent'...
  3. Install and build

    The first command downloads the libraries it depends on. The second turns the source code into something runnable.

    $ npm install && npm run build
    added 214 packages in 18s
  4. Make singularity available everywhere

    This lets you type singularity from any folder instead of the full path.

    $ npm link
    added 1 package
  5. Check that it works

    This lists every network it knows about. No lookup, no account, no API key — if you see a table, you're ready.

    $ singularity chains
      ID          NAME          FAMILY  CHAIN ID     ASSET  ALIASES
      ethereum    Ethereum      evm     1            ETH    eth, mainnet, l1
      base        Base          evm     8453         ETH
      arbitrum    Arbitrum One  evm     42161        ETH    arb, arbitrum-one
      solana      Solana        svm     —            SOL    sol
      bitcoin     Bitcoin       utxo    —            BTC    btc
      cosmoshub   Cosmos Hub    cosmos  cosmoshub-4  ATOM   cosmos, atom, gaia
    
    
      32 chain(s).

Getting started

Your first real command

Let's look inside a wallet. This one belongs to Vitalik Buterin, a co-founder of Ethereum — it's public, like every address on a blockchain.

$ singularity balance vitalik.eth --chain ethereum
ethereum
────────
  6.71259795 ETH  (native)

  37.192124   USDC  0xA0b86991…06eB48
  290.368219  USDT  0xdAC17F95…831ec7
  4.57207827  DAI   0x6B175474…271d0F
  1.46189817  WETH  0xC02aaA39…756Cc2

  EVM chains cannot be enumerated without an indexer, so this covers a curated
  list of major tokens only. Pass `tokens` with contract addresses to check others.
  https://etherscan.io/address/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
Real output from a live run. Balances change constantly, so yours will differ.

Reading the command

PartWhat it is
singularityThe tool itself.
balanceWhat you want — the question you're asking.
vitalik.ethWho you're asking about. A name, an address, or a nickname you've saved.
--chain ethereumWhich network to look on. -c is the short form.
Notice what it told you The grey note at the bottom is deliberate. On Ethereum there is no way to list every token a wallet holds without a paid indexing service, so the tool checks a curated list of major ones and says so. It would rather tell you the shape of the answer than let you assume it found everything.

Add --json to any command to get machine-readable output instead of a table.


Try it here

Run it without installing it

A working terminal, with the real answers. Every response below was captured from an actual run against live networks — nothing here is mocked up to look good, including the two that refuse to answer.

$ singularity
Arrow keys walk back through what you have typed. help lists everything the demo knows; clear wipes the screen.
The two that say no are the point Ask for Ethereum history without an indexer key and it tells you it has no answer, rather than handing back an empty list that reads as "this wallet has done nothing". Ask Stride for a token whose decimals the chain never declares and it gives you base units instead of a number scaled by a guess. Both are real, and both are the reason the rest of the output is worth trusting.

The other way to use it

Ask Claude instead of typing commands

MCP (Model Context Protocol) is a standard way to give an AI assistant real tools. Without it, an assistant answering “what's in this wallet?” is recalling something from training data — possibly years stale, possibly invented. With it, Claude runs the same commands you would and reads the actual, current answer off the chain.

The quickest way

One command, run from anywhere. Use the full path to wherever you cloned the repo, and make sure you've run npm run build first.

$ claude mcp add singularity -- node /path/to/Singularity-Agent/dist/mcp/server.js
 Added stdio MCP server singularity

Or install it as a proper plugin

The repo doubles as its own single-plugin marketplace, so this is two steps. Run the first one from the folder containing Singularity-Agent — the path has to be in ./name or absolute form, and a bare . is rejected.

$ claude plugin marketplace add ./Singularity-Agent
 Successfully added marketplace: singularity
$ claude plugin install singularity-agent@singularity
 Successfully installed plugin: singularity-agent@singularity (scope: user)
/plugin install does not take a folder path It expects a plugin-name@marketplace-name id. Handing it a path fails with “Marketplace not found” — add the marketplace first, as above. Both commands also work inside a session as /plugin marketplace add and /plugin install.

Check it landed with claude plugin list.

Then just ask

  • “What's in vitalik.eth right now?”
  • “What did transaction 0xc29d744… actually do?”
  • “Is it cheap to send Bitcoin at the moment?”
  • “Prepare a transfer of 25 USDC on Base to this address.”

The eighteen tools Claude gets

ToolWhat it does
chainsList every supported network.
resolveIdentify what a piece of text is and which chains it belongs to.
balanceHoldings for one address on one chain.
portfolioOne address across many chains at once.
transactionLook up and explain a transaction.
blockFetch a block by height, hash, or latest.
feesWhat a transfer costs right now.
read_contractRead data out of a smart contract.
decodeTurn raw transaction data into a readable function call.
historyWhat an address has been doing, newest first.
mint_auditWhat a Solana mint can still do to you — who can mint more, who can freeze.
token_identityWhether a token is the one it claims to be.
verify_burnConfirm a burn from its signature, at finalized commitment.
build_transferPrepare an unsigned payment.
build_burnPrepare an unsigned burn.
chain_livenessWhether a chain is still producing blocks, rather than merely answering.
inspect_exitBefore you buy: what could stop you selling it again.
receipt_artWhat a payment receipt looks like, and whether an image is genuinely it.

Every one of them is marked read-only, and build_transfer returns a payload plus a list of warnings that Claude is instructed to show you before you sign anything. history on an Ethereum-style chain needs an indexer key; without one it says so rather than returning an empty list that reads as "nothing ever happened here".


Recipes

What you can ask it

Each of these is a real command with real output. Copy any of them and run it.

What even is this thing I pasted?

You have a string of characters and no idea whether it's a wallet, a transaction, or a typo. resolve works it out — and if it's a name, looks up the address behind it.

$ singularity resolve vitalik.eth
  Input    vitalik.eth
  Kind     name
  Address  0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
  Name     vitalik.eth
  Family   evm
  Chains   ethereum

  Resolves through ENS on Ethereum mainnet; the resulting address works on
  every EVM chain.

Show me everything, everywhere

portfolio checks one address across many chains at once. It only queries chains where that address format is actually valid, so an Ethereum address doesn't produce a pile of Solana errors.

$ singularity portfolio vitalik.eth
Portfolio for 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
──────────────────────────────────────────────────────
  Queried 5 chain(s).

ethereum
────────
  6.71259795 ETH  (native)
  37.192124   USDC

base
────
  0.04182 ETH  (native)

  Empty on: arbitrum, optimism, polygon

What did this transaction do?

Paste a transaction hash with no chain and it searches the likely ones in parallel. It also decodes the raw data into a readable function call where it recognises it.

$ singularity tx 0xc29d74412da1bec4e662a7978c3ef993beed7833219d3362a2abca09700fdaa5
base  success
─────────────
  Hash      0xc29d74412da1bec4e662a7978c3ef993beed7833219d3362a2abca09700fdaa5
  From      0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001
  To        0x4200000000000000000000000000000000000015
  Value     0 ETH
  Block     51344342
  Time      2026-09-15T13:13:51.000Z

  0xdead…0001 -> 0x4200…0015 on Base.

  https://basescan.org/tx/0xc29d744…
You never told it this was on Base — it found it.

Is it expensive to send right now?

Fees work completely differently on each chain. fees normalises them to one comparable number, then shows you the chain's own units underneath.

$ singularity fees --chain bitcoin
Fees on bitcoin
───────────────
  Simple transfer  ~0.00000054 BTC

  nextBlock      1.1 sat/vB
  within6Blocks  0.4 sat/vB
  within24Hours  0.3 sat/vB
  assumedTxSize  141 vB (1 input, 2 outputs, P2WPKH)

  Bitcoin fees are per-vbyte, so cost depends on how many UTXOs you spend,
  not on the amount sent.

What is this wall of hex?

When a wallet asks you to approve something, it often shows an unreadable blob. decode tells you what it actually calls and with what arguments — worth doing before you approve, not after.

$ singularity decode 0xa9059cbb000000000000000000000000d8da…0f4240
{
  "selector": "0xa9059cbb",
  "signature": "function transfer(address to, uint256 amount) returns (bool)",
  "name": "transfer",
  "args": [
    { "name": "to",     "type": "address", "value": "0xd8dA6BF2…aA96045" },
    { "name": "amount", "type": "uint256", "value": "1000000" }
  ]
}
Translation: send 1,000,000 base units — 1 USDC, which has 6 decimals — to that address.

Prepare a payment for me

This is the one command that produces something you could eventually sign. Note that nothing is sent, and no key is involved.

$ singularity build --chain base --to vitalik.eth --amount 25.5 --token USDC
Unsigned transaction — base
───────────────────────────
  Send 25.5 USDC (0x8335…2913) to 0xd8dA…6045 on Base.

  Payload
    {
      "to":      "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "value":   "0x0",
      "data":    "0xa9059cbb000000000000000000000000d8da…01851960",
      "chainId": 8453
    }

  How to sign
    This calls transfer() on the token contract. `to` is the TOKEN address, not
    the recipient — the recipient is encoded in `data`. Sign with your own wallet.

  Warnings
    ! This transaction is unsigned. Review every field before signing.
    ! Verify the token address belongs to the asset you mean. Fake tokens
      reuse real symbols.

  Singularity holds no keys and has not signed or broadcast anything.
Read the warnings, every time That second warning is not boilerplate. Anyone can create a token called “USDC”. The only thing that identifies a real one is its contract address — which is why the tool prints it and asks you to check.

Why is everything slow?

Singularity talks to public servers that are free and therefore heavily rate-limited. doctor tells you which ones are actually responding.

$ singularity doctor
Endpoint health
───────────────
  ok  ethereum   440ms
  ok  base       216ms
  ok  arbitrum   212ms
  ok  solana     190ms
  ok  bitcoin    21403ms
  ok  cosmoshub  516ms
  ok  osmosis    513ms
  ok  celestia   723ms

  All endpoints reachable.
That 21-second Bitcoin result is a slow public server, not a broken one. Configuration shows how to use a faster one.

Tell me when this changes

watch keeps asking and prints only what moved. It works on a balance, a chain's head, one transaction until it's confirmed, or the health of several chains at once.

$ singularity watch tip -c solana -i 2
Watching solana
───────────────
  Polling. Ctrl-C to stop.

18:44:23  #448546031  (first reading)
18:44:25  #448546039  +8
18:44:27  #448546047  +8
Real output. -i is seconds between checks; add -n 3 to stop after three changes.
It asks repeatedly — it doesn't get pushed to There's no live feed underneath this. It checks on a timer, so something that changed and changed back between two checks is something it never saw. That's a real limit and it's printed in singularity watch --help rather than left for you to discover.

New in v0.2.0

Getting paid, and proving it

Every payment tool answers one question — did a transaction land — and hands back paid: true. That single word hides three things you need to know before you ship anything, so Singularity Pay keeps them apart.

How settled is it?

Four answers, not two. Confirmed and finalized are different claims on Solana, and only one of them cannot be reversed. A tool that calls both of those "paid" is asking you to hand over goods against a transaction that can still vanish.

Were you paid what you asked?

A transaction that lands is not a transaction that paid you, in that token, for that amount. Anyone can make a token called USDC, and a payment in the fake one arrives just as smoothly. Every mismatch is named.

Can it be taken back?

Some tokens let whoever issued them freeze your balance, or move it out of your wallet without you signing anything. That gets checked before the payment link is ever shown to anybody.

TG /pay 0.25 --to 7xKX...gAsU --sender 9WzD...AWWM
 Payment request for 0.25 SOL

  To        7xKX...gAsU
  Sender    9WzD...AWWM — balance 1.84 SOL, enough
  Reference 695xPtsS...  — how this payment is found on chain

[ a QR code image follows, in this payment's own colours ]

Scan it with Phantom. Singularity holds no keys and cannot sign.
The sender's balance is read before the code is shown, so a wallet that cannot cover the payment fails here rather than on your customer's approval screen.

The code is a picture of that one payment

Every payment carries a reference — a one-off value attached to the transfer so it can be found on chain. The artwork is calculated from it. Nothing is stored, which is the whole point: two payments can never look alike, the same payment always looks identical, and anyone holding the reference can redraw it and compare.

Colour varies. Contrast does not. Every palette is measured against the background and darkened until it clears the threshold a scanner needs — because lightness is not brightness, and a sweep of 400 colour schemes found one that looked perfectly good and sat well below what a cheap camera can read.

A receipt you can check, not just keep

Once a payment is finalized it can be minted as an NFT of that same picture. It refuses to mint for a payment that is merely confirmed, or that does not match what was asked for — a receipt is evidence, and evidence built from a request rather than a result is just a nicely formatted claim.

The image is not stored on the blockchain, and we are not going to pretend it is. There is room for 200 characters; the picture is about 30,000. So the seed goes on chain instead, and the picture is calculated from it. If whoever hosts the image swaps it for a different one, the swap simply fails to verify — ask Claude, or the bot, and it will tell you.

TG /receipt 695xPtsSYaSALQdwgE6WxC4zX49zZrpVPwF2uiUGjCBB
Receipt 695xPtsS

  Palette   moss/indigo
  Modules   dot
  Finders   rounded
  Contrast  12.6:1 ink, 8.9:1 accent

Derived from the reference alone, so anyone holding it gets this
same answer without trusting a server.
A mismatch means the image is not evidence of the payment. It does not mean the payment was bad, and the tool says so rather than letting anyone imply otherwise.

One honest footnote. Creating any new token on Solana requires that token's own key to sign for its creation — there is no way around it. So a throwaway key is made, used for that one signature, and thrown away. It never holds funds, and once the receipt exists it can do nothing at all. Your wallet is still the only thing that signs for anything of value, and it is still the only thing holding your money.


For developers

Build something on it — the SDK

Everything above asks one question and reads one answer. An application is different: it runs for weeks, asks the same question hundreds of times an hour, and sooner or later has to write. singularity-sdk is the package for that — a separate install, versioned separately, built on the same engine as the commands on this page.

$ npx singularity-sdk new my-app --template reader
 Created my-app from the "reader" template.

  cd my-app
  npm install
  npm start

It reads public endpoints and needs no key to run.
Three templates: reader, monitor, agent. All of them run on the first try.

The same answers, in code

Set your defaults once, then ask. The result carries the same honesty the terminal output does — including the note about what a token list covers.

TS app.ts
import { createSingularity } from 'singularity-sdk';

const sdk = createSingularity({ chain: 'ethereum', budget: { maxItems: 8 } });

const balance = await sdk.balance({ address: 'vitalik.eth', includeTokens: true });

balance.native.amount.formatted    // '6.71259795'
balance.tokenCompleteness.kind     // 'curated' — read this before the list

Watching, rather than asking again

Poll a balance, a chain's head, or one transaction until it's confirmed. These are polling loops and the SDK says so plainly — there's no push feed hiding underneath.

TS monitor.ts
sdk.watch.balance({ address: 'vitalik.eth' }, ({ value, previous }) => {
  if (!previous) return;          // the first reading isn't a change
  notify(previous.native.amount.formatted, value.native.amount.formatted);
}, { intervalMs: 15_000 });

Your keys stay yours — still

The tool on this page cannot sign, and neither can the SDK. But an app that can only read isn't much of an app, so the SDK defines the shape of a signer and ships none: you plug in the browser wallet, hardware device or key service you already use, and it never hands a secret to the library.

Until you do, the write methods don't exist — and your editor says so before you ever run anything.

TS read-only.ts
const sdk = createSingularity({ chain: 'ethereum' });

await sdk.build.transfer({ to: 'vitalik.eth', amount: '0.1' });  // fine
await sdk.write.transfer({ to: 'vitalik.eth', amount: '0.1' });
             ~~~~~
Property 'transfer' does not exist on type 'SignerRequired'.
It also makes your app an agent The sixteen tools Claude uses are defined once in this project. The SDK hands you the same set in Anthropic, OpenAI-style and MCP shapes, with a hook to approve or refuse each call before it runs — so anything you build can be driven by a model too, without you transcribing a single tool definition.

Full documentation, the signer guide and four runnable examples: singularity-sdk on GitHub.


Coverage

32 chains, four families

A family is a group of chains that work the same way underneath. Learn one member and you have effectively learned the rest. You can add any chain that isn't listed here yourself — see Configuration.

evm

Ethereum & friends

Addresses start 0x. Hundreds of chains share this design.

  • ethereum
  • base
  • arbitrum
  • optimism
  • polygon
  • bsc
  • avalanche
  • gnosis
  • scroll
  • linea
  • zksync
  • sepolia
  • base-sepolia
svm

Solana

Addresses are base58 text with no prefix. Token holdings can be listed in full.

  • solana
  • solana-devnet
utxo

Bitcoin & kin

Addresses start bc1, 1 or 3. No tokens — just coins.

  • bitcoin
  • bitcoin-testnet
  • litecoin
cosmos

Cosmos

Each chain has its own address prefix, which makes them self-identifying.

  • cosmoshub
  • osmosis
  • celestia
  • injective
  • dydx

You can refer to a chain by its id, a nickname, or its numeric id — eth, ethereum, mainnet and 1 all mean the same thing. Get it wrong and it suggests what you probably meant.


Plain English

Words you'll see

Crypto has a lot of jargon. Here is the subset you actually need to use this tool.

Address
A public account identifier — like a bank account number. Safe to share; that is what it is for. Every chain family writes them differently.
Private key
The secret that controls an address. Never share it, never type it into anything. Singularity never asks for one.
Transaction hash txid · signature
The receipt number for something that happened on-chain. Paste one into tx to see what it did.
Native token
The coin a chain runs on, used to pay fees — ETH on Ethereum, SOL on Solana, BTC on Bitcoin, ATOM on Cosmos Hub.
Token
Anything else living on that chain, like USDC. Identified by a contract address, which differs on every chain — the same-named token has a different address on Ethereum and Base.
Base units wei · satoshi · lamport
Chains store whole numbers only, so amounts are held in tiny units. 1 ETH is 1018 wei; 1 BTC is 100,000,000 satoshi. Singularity shows you both, and refuses to quietly round.
Gas / fee gwei · sat/vB
What you pay the network to process your transaction. It fluctuates with demand, which is why fees exists.
RPC endpoint
The server Singularity asks for data. Free public ones are included; they are slow and rate-limited. See Configuration.
ENS name
A human-readable name for an Ethereum address, like vitalik.eth. Use it anywhere an address is accepted.
Unsigned transaction
A prepared but unsigned instruction. Harmless on its own — it does nothing until a private key signs it, which happens in your wallet, not here.
Smart contract
A program stored on a chain. read_contract reads data out of one; it never writes to one.

Going further

Configuration

Faster connections

The bundled public servers need no signup, which is why they're the default — but they are throttled and sometimes just disappear. Providers like Alchemy and Infura give free API keys with far better limits. Point Singularity at one:

$ export SINGULARITY_RPC_ETHEREUM=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
# The name is SINGULARITY_RPC_ + the chain id, uppercased, with - becoming _
# So base-sepolia becomes SINGULARITY_RPC_BASE_SEPOLIA
# Comma-separate several for automatic failover.

Nicknames and custom chains

Create ~/.singularity/config.json to save addresses under names you'll remember, and to add chains that aren't built in:

{} ~/.singularity/config.json
{
  "addressBook": {
    "savings": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
  },
  "portfolioChains": ["ethereum", "base", "solana"],
  "chains": [
    {
      "id": "my-rollup",
      "family": "evm",
      "chainId": 123456,
      "nativeCurrency": { "name": "Ether", "symbol": "ETH", "decimals": 18 },
      "rpc": ["https://rpc.my-rollup.example"]
    }
  ]
}

Now singularity balance savings -c base works, and my-rollup is a chain like any other.


Troubleshooting

If something goes wrong

Errors from this tool carry a code and a hint. The hint is usually the fix.

“singularity: command not found”

Step 4 of the install didn't take. Run npm link again inside the project folder. If that fails, you can always run it directly:

$ node dist/cli/index.js chains
“RPC call failed”, or everything is very slow

A public server is rate-limiting you. Check which ones are alive with singularity doctor, then set your own endpoint — see Configuration. This is the single most common problem, and the fix is free.

“is not a valid address on Osmosis”

Cosmos chains each use their own address prefix, but they're all the same underlying account. The tool does the conversion for you rather than just complaining:

$ singularity balance cosmos1qypqx…lzv7xu -c osmosis
  INVALID_ADDRESS  "cosmos1qypqx…lzv7xu" is not a valid address on Osmosis.
  That is a "cosmos" address. It is the same account on Osmosis, re-encoded:
  osmo1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5helwsw

Copy the address it gives you. singularity resolve on any Cosmos address lists every equivalent at once.

“Transaction was not found”

Three likely reasons. It might be on a chain outside the default search set — name it with --chain. It might be too new and still pending. Or, on Solana, it might simply be too old: public Solana servers delete old history, and retrieving it needs an archival endpoint.

A token I own isn't showing up

Expected on Ethereum-style chains — see Limits. Name the token explicitly by its contract address:

$ singularity balance 0xYourAddress -c base --token 0xTokenContractAddress
“Unknown chain”

Check the spelling against singularity chains. The error also guesses what you meant — typing etherium suggests ethereum.


Honesty

What it deliberately won't do

These are real boundaries, not bugs. They're listed here, and in the tool's own output, because a confident wrong answer is worse than a clear “I can't”.

  • Ethereum token lists aren't complete. Listing every token an address holds requires a paid indexing service. Without one, the tool checks a curated set of major tokens and says so. Solana and Cosmos can list everything, and do.
  • No prices. It reports quantities, not dollar values.
  • IBC tokens show as hashes. On Cosmos, a transferred token appears as ibc/3EF74C…. Identifying it needs a per-token lookup, so it shows the hash rather than guessing.
  • Cosmos fees are an estimate. Gas prices there are set by individual validators, not the chain. Your wallet will usually re-quote.
  • No CosmWasm contract queries. Contract reads cover Ethereum-style chains and Solana.
  • It cannot send anything. By design, permanently.