What it does
Compass turns application requests into consistent, non-authoritative intents. It classifies position actions and can create a complete SOL or original SPL-token payment request, including its Solana Pay transfer URI.
Use it between an application decision and execution policy. It helps the next component understand what was requested; it does not establish whether a recommendation is sensible, which wallet may act or whether funds exist.
Use independently
Select uk.capp.sidecar.solana-compass in local-intent mode. No RPC, wallet, Edge or price feed is required. Use window.capp.solana.compass or the portable client.
Preserve the business operation and position IDs when shaping an intent. For a payment request, save the complete normalized result at your trusted application/server boundary; the URI alone is not its complete validity policy.
Provider dependencies
| Method / mode | Dependency | Behaviour |
|---|---|---|
classify() | No peers | Local classification, including in an externally configured Compass. Unknown actions become non-executable previews. |
intent() with local-intent | No peers | Shapes an intent and its digest; no persistence, signing or submission. |
intent() with external-adapter | Your configured adapter | Requests action intent; the service owns its classification/validation contract. |
paymentRequest() | local-intent only | Local request normalization and hashing. External mode is rejected for this method. |
Compass is optional in Edge's simple payment flow. Installing Compass does not automatically apply group review, choose an execution bucket or run a strategy.
First successful intent
Call classify() with a known action, then with an unknown action. An opening/increase is exposure-increasing; close/reduce/exit is risk-reducing; hold and unknown actions are not executable. reason labels such as stop-loss are classification inputs, not evidence that an actual position was closed.
For intent(), inspect positionEffect, sendIntent, executable, nonExecutablePreview, authority and intentDigest. Local authority.authoritative is false. Keep actual network policy in Sentinel/Latch: non-token intent() is a shaper rather than a verified RPC-network guard.
Create a saved devnet payment request
Copy the client module alongside this module. Obtain the real recipient and a fresh reference from the payment helpers when creating the request, then persist that reference and the timestamps. Do not regenerate them on retry. This helper is inert until called and performs no payment.
import {createSolanaClient} from './solana-client.mjs';
const client = createSolanaClient(() => window.capp?.solana);
export async function makeDevnetRequest({requestId, recipient, reference, amountAtomic, createdAt, expiresAt}) {
const status = await client.call('compass', 'status');
if (!status.ready || status.providerMode !== 'local-intent' || status.network !== 'devnet') {
throw new Error('Configure local Compass for devnet');
}
return client.call('compass', 'paymentRequest', {
requestId, network: 'devnet', recipient, reference,
asset: {kind: 'native', decimals: 9}, amountAtomic,
createdAt, expiresAt, label: 'Example request', message: 'Review before paying'
});
}amountAtomic: '10000' requests 10,000 lamports, not 10,000 SOL. createdAt and expiresAt are integer Unix seconds, not Date.now() milliseconds. Expect a capp.solana-payment-request.v1 result containing requestDigest, genesisHash, normalized asset, reference, times and uri.
The standard transfer URI does not carry this request's network or expiry. Display those constraints alongside it, retain the full request for verification and use Edge's preparePayment() for the integrated devnet path. A wallet accepting the URI is not proof of a matching, paid invoice.
Amounts, identity and classification
| Input | Meaning |
|---|---|
amountLamports in a native intent | A safe integer lamport amount. It is not a floating-point SOL amount. |
amountAtomic in a token intent or payment request | A decimal integer string. Use exact helpers for human-unit conversion, not floating-point multiplication. |
asset for a token | Exact network, original Token Program, mint and decimals; a symbol such as USDC is not an identity. |
createdAt | Intent creation time is generated in seconds; save the returned intent for later evaluation. |
intentDigest | Deterministic content binding excluding generated creation time; not a signature or permission. |
Token intents require kind: payment, a supported spl-token asset and amountAtomic; mixing in amountLamports is refused. A native payment request instead uses an asset descriptor such as {kind: native, decimals: 9} and a string atomic amount. Preserve the different method shapes rather than copying fields between them blindly.
Scope and limitations
An intent does not choose a wallet, authorize a payment or establish that a trade is safe. Payment requests contain explicit network/expiry alongside a Solana Pay URI; the standard URI does not encode those constraints.
Local Compass is not a durable invoice store and does not enforce request-ID uniqueness across separate calls. Your application must prevent one business request ID from being issued with conflicting terms. Unknown market actions remain previews; do not turn hold_only into an executable action downstream.
Application API
The owning interface is window.capp.solana.compass. The portable client calls the same methods. This table describes main arguments, not a stricter typed guarantee than the current provider implements. Exact transaction/provider bindings must be preserved; unsupported state or arguments are rejected.
import {createSolanaClient} from './solana-client.mjs';
const client = createSolanaClient(() => window.capp?.solana);
const status = await client.call('compass', 'status');status
client.call('compass', 'status', input)
Main input: No arguments required.
Read intent-provider mode and readiness; never grants authority.
classify
client.call('compass', 'classify', input)
Main input: kind, action or tradeType; optional reason and positionSide.
Classify payment/position intent. Unrecognised and hold-only requests remain non-executable previews.
intent
client.call('compass', 'intent', input)
Main input: operationId; network, kind, recipient and amount fields appropriate to the request.
Normalize request metadata and produce a digest-bound intent. Does not select a wallet or execution resource.
paymentRequest
client.call('compass', 'paymentRequest', input)
Main input: requestId, network, recipient, asset, amountAtomic, reference, createdAt, expiresAt; optional label, message, memo.
Create a versioned request and Solana Pay URI. Uses the local provider. Explicit network and expiry remain separate request constraints.
Troubleshooting
| Symptom or error | Next step |
|---|---|
| Intent is non-executable | Check the action/kind and hold/unknown classification. Do not override it by relabelling the result. |
PROVIDER from paymentRequest() | Use local-intent; external intent shaping is a different method contract. |
| Network mismatch | Match the request to the configured network. Never infer the chain from the URI alone. |
| Invalid amount or asset | Keep atomic amounts as strings, native intent lamports as safe integers and token identity explicit. |
| Same request ID produces different digests | Compare saved times, reference, recipient, asset and amount. Enforce uniqueness at the business owner. |
Verify your integration
Test hold/unknown classification, a supported close, exact request reconstruction, invalid decimals, changed recipient and expired request handling downstream. A successful Compass response should produce zero wallet approvals, submissions and fulfilment operations.
Integration recipes
Composition · Devnet payment · Recovery · Typed client · Schemas
Related data contracts
These schemas describe payload shape, not evidence of approval or successful execution. Match the version in your payload; older versions remain listed for compatibility.
Configuration reference
These are the selected package's configuration fields. String credential values and installation-specific defaults are never published here. A field's presence does not bypass its runtime policy.
| Field | Type | Meaning and constraints |
|---|---|---|
providerMode | select | Select the implementation this build will use. Configuring an endpoint does not verify its connection or behavior.. Choices: local-intent, external-adapter |
network | select | Must match the live provider and requests. Arena and demo confirmation always use simulation.. Choices: devnet, testnet, mainnet-beta, demo |
defaultAsset | text | Fallback asset symbol for shaped intents. This does not add token-program support by itself. |
externalAdapterUrl | text | Absolute HTTPS endpoint, or loopback HTTP for development. Keep private credentials on the backend; packaged configuration is visible to users. |
Agent interfaces
These names are declared by the package for host/Agent integration, not JavaScript methods to invoke directly. The host must register a tool, grant its scope and enforce its approval policy. A manifest declaration alone does not prove availability in every Agent catalogue. Prefer the application API above when integrating your own app.
| Tool | Declared risk | Approval requirement |
|---|---|---|
solana.compass.status | low | mode-policy |