The AI Code Assistant includes Stellar/Soroban developer tooling: safe network configuration, a read-only Horizon service, a read-only Stellar RPC (Soroban RPC) client, heuristic project detection, contract/account inspection, and Stellar-aware AI analysis.
Honest status: everything below is implemented and tested. Anything not listed below should be assumed not implemented yet (see What is not implemented).
Stellar/Soroban developers spend significant time on contract structure, dependency hygiene, network configuration, and code review. The assistant helps by:
- Recognizing a Soroban/Stellar project when it is imported (with explicit confidence, and never misclassifying plain Rust).
- Providing a read-only, SSRF-safe view of live Stellar network data (network health, ledgers, accounts, contracts, ledger entries, transactions, events).
- Running AI analyses grounded in the actual contract files, manifests, and Stellar configuration.
All Stellar data flows through the existing authorization boundaries: a user can only analyze projects they own, and the RPC/Horizon clients only read public network data bound to the configured network.
| Variable | Default | Description |
|---|---|---|
STELLAR_NETWORK |
testnet |
mainnet | testnet | futurenet | custom |
STELLAR_HORIZON_URL |
(preset) | Override Horizon endpoint |
STELLAR_RPC_URL |
(preset) | Override Stellar RPC endpoint |
STELLAR_REQUEST_TIMEOUT |
15 |
Outbound request timeout (seconds) |
STELLAR_MAX_RESPONSE_BYTES |
2097152 |
Cap on response body size |
STELLAR_RPC_MAX_KEYS |
100 |
Max ledger keys per getLedgerEntries call |
STELLAR_STRICT_HOST_VALIDATION |
1 |
DNS-verify public hosts resolve publicly |
Defaults are testnet, so nothing touches real XLM unless explicitly configured. Explicit endpoints are validated before use (see Endpoint safety).
mainnet,testnet,futurenet— official public endpoints (Horizon + RPC).local/custom— loopback-only configuration for a localstellar-core/stellar-rpc.
Logged-in users can switch the network their read-only Stellar requests and
analysis use from the Network status panel on /stellar (or via
GET/PUT /stellar/api/network). Only the fixed supported networks
(testnet, mainnet, futurenet, custom) are selectable — never a raw URL,
so SSRF/endpoint validation is untouched. The choice is stored per user
(users.stellar_network); with no stored selection the operator-configured
STELLAR_NETWORK remains authoritative, and mainnet is never an implicit
default — it only takes effect after an explicit user selection. The selected
network routes through StellarService, SorobanRpcClient, and the Stellar
analysis context inside authenticated requests.
get_network_info()— network metadata (never contacts the node).validate_address(address)— structural G-address validation.get_account(address)— bounded account lookup.get_transaction(hash)— bounded transaction lookup.get_ledger(sequence)— bounded ledger lookup.get_assets(cursor, limit)— bounded issued-asset list.get_account_transactions(address, limit)— bounded account history.
SorobanRpcClient implements the read-only subset of the current Stellar
RPC API (see docs/soroban.md): getHealth, getVersionInfo,
getLatestLedger, getNetwork, getLedgerEntries, getLedgers,
getTransaction, getTransactions, getEvents, getFeeStats. It never
implements sendTransaction or simulateTransaction.
Minimal, fixture-verified encoders for SEP-23 strkeys (with full CRC16
checksum validation) and the LedgerKey values used by getLedgerEntries
(account, contract-instance, contract-code). Contract/account inspection
therefore validates addresses properly rather than structurally only.
network_status()— configured network + best-effort live RPC health / latest ledger (honest when the RPC is unreachable).inspect_account(address)— parsed account data plus ledger freshness.inspect_contract(contract_id, wasm_hash=None)— the contract's instance ledger entry and (optionally) its deployed wasm metadata. Supported contract-data/contract-code entries are decoded into a structured view (instance_entry["decoded"],code_entry["decoded"]); the raw XDR is returned bounded alongside it.inspect_ledger_entry(key)— a live ledger entry by base64LedgerKey, with the same decoded view where the entry type is supported.
Contract-data decoding lives in app/services/stellar_xdr_decode.py (bounded
LedgerKey/LedgerEntryData/SCVal decoding, pinned by fixtures): a contract
instance entry decodes into its contract id, durability, executable wasm hash
and storage, and a contract-code entry into its wasm hash + byte size (raw wasm
bytes are never dumped). Unsupported entry types and malformed XDR are reported
explicitly as undecodable — decoded values are never guessed at.
The same module adds a bounded, read-only transaction-envelope decoder,
decode_transaction_envelope(base64_xdr) (pinned by round-trip fixtures):
V1, legacy V0, and fee-bump envelopes decode into source account, fee (stroops
- exact lumens), sequence, memo, preconditions, signatures, and operations. Supported operations are payment, create account, change trust, bump sequence, invoke host function (contract, function name, argument count, and a bounded view of the Soroban auth entries — signature bytes are never dumped), extend footprint TTL, and restore footprint. Amounts are presented in stroops with an exact lumen string. Any other operation type is reported explicitly as unsupported; because each operation has a variable-length layout, decoding stops at that operation and the remaining operations/signatures are honestly marked not parsed rather than guessed at. Malformed/truncated XDR returns an explicit undecodable result.
detect_stellar_project(files) classifies an indexed project:
- likely — Soroban crate in
Cargo.toml, or#[contractimpl]/#[contract]attributes /soroban_sdk::imports in Rust sources. - possible — Stellar SDK dependency (JS/Python/Go), a
stellar.toml/soroban.toml/.sorobanconfig, acontracts/layout, or Stellar/Soroban CLI tooling in build/CI files and shell scripts (Makefile/Justfile/Dockerfile,build.rs/xtask, GitHub Actions workflows, GitLab CI (.gitlab-ci.yml), CircleCI (.circleci/), Travis (.travis.yml), and*.shscripts). Tooling detection is command-fragment based (soroban contract …,stellar xdr …, …) — merely mentioning “Stellar/Soroban” in a README or keyword-only comments never triggers it. - none — otherwise. A plain Rust crate is never classified as Soroban.
detect_stellar_network(files) extracts a network hint (testnet/mainnet/
futurenet) from config passphrases and file names — never from live data.
Detection metadata is attached to every import response and exposed via
GET /workspaces/api/projects/<id>/stellar.
The full signal model, confidence semantics, why plain Rust is excluded, and how
to add new signals without false positives are documented in
stellar-detection.md.
Three analysis kinds: stellar (project overview for a Stellar developer),
stellar_security (Soroban-aware security review), and stellar_config
(a review of the detected Stellar configuration files). All three:
- Run the same content-access gate as every other analysis (owner-only, fails closed).
- Report honestly when the project is not Stellar.
- Ground claims in the indexed files, mark
[CONFIRMED]vs[SUGGESTION], and include an honest live-RPC availability note.
stellar_config reviews only the detected configuration files
(stellar.toml, soroban.toml, stellar-config.toml, stellar.json,
soroban.json, and .soroban/ files) for internal consistency and obvious
misconfigurations — e.g. a testnet passphrase paired with a mainnet RPC
endpoint, placeholder endpoints, or conflicting network definitions. It is
gated on detection (non-Stellar projects get the honest "not applicable"
result), and it marks everything [SUGGESTION] unless a file directly proves
the fact.
The stellar_security model is asked to close its narrative with a bounded
JSON findings block. That block is parsed defensively — malformed or
missing JSON never crashes or alters the analysis; the narrative is returned
unchanged and nothing is persisted:
- Values are normalized to a shared vocabulary (severity, Stellar category,
confidence), length-bounded, capped at 50 findings, and never invented from
prose.
[CONFIRMED]/[SUGGESTION]markers map toconfirmed/suggestion. - Findings are persisted per project as
StellarSecurityFindingrows (the analysis request commits atomically with its activity row). Re-running an analysis replaces the previous run's findings. - Findings are evidence, not verdicts — the narrative itself states the AI never claims formal verification or proven vulnerabilities.
- Non-Stellar projects always receive the honest "not applicable" result with an empty findings list and nothing is persisted.
Findings ride along in the stellar_security analysis API response and are
read back owner-scoped via
GET /workspaces/api/projects/<id>/stellar/security-findings (same 404-on-
non-owner gate as every project surface, so there is no existence oracle).
Display in the project developer panel is handled by the results-panel UI.
- A Stellar section in the main navigation (
/stellar) — a read-only developer page with live network status (and explicit per-user network selection), account inspection, contract inspection, and ledger-entry lookup. Supported contract-data/code entries are decoded into a structured view with the bounded raw XDR shown alongside; every lookup has loading, empty, error, and timeout states. Shared rendering lives inapp/static/js/stellar_tools.js. - A Stellar tab in the project explorer — per-project detection (confidence, evidence, network hints) with the relevant files linked to the file viewer, plus the same live read-only network status and account/contract/ledger-entry lookups so a developer can inspect the project and its on-chain data in one place. Detection evidence and relevant files come from the indexed project only; the live lookups are bound to the configured network and never accept a URL from project content.
- Import feedback — the workspace import flow surfaces detection at import
time: a detected (Stellar/Soroban) project shows a confidence badge with
links to open the project or jump straight to its Stellar tab
(
?tab=stellar); non-Stellar imports behave exactly as before (detection is read-only and non-blocking).
flask stellar network, validate <address>, account <address>, health,
contract <id>, ledger-entry <key>, config — all read-only and scriptable:
- Add
--jsonto any command for a stable, parseable JSON document (network info, validation result, account, health, contract, ledger entry, or generated config). Human-readable output is the default and is unchanged. flask stellar config [--network <net>] [--path <path>] [--overwrite] [--existing <path>]generates a reviewable.soroban/config.tomlfor the selected network (testnet/mainnet/futurenet/custom) from the app's validated presets. It writes no files, emits no secrets, and refuses to overwrite a path listed via--existingunless--overwriteis passed. The format is the same one the scaffold and detector already understand, so the output round-trips through detection.- Errors are printed to stderr and never leak stack traces; when
--jsonis given the error is emitted as a JSON object with anerrormessage. - Exit codes are documented:
0success,2service error / not found / RPC unreachable,3invalid input (address/contract/key/hash/network).
validate_endpoint_url enforces:
http/httpsschemes only.httpsrequired for public networks (mainnet/testnet/futurenet), and no private/link-local/loopback IP literals or obviously-private hostnames.- Loopback hosts only (
localhost,127.0.0.1,::1) for custom networks. - Requests are restricted to the configured base URL, redirects are refused, public hosts are DNS-verified to resolve publicly, and every request enforces a timeout and a response-body cap.
Endpoint URLs come exclusively from configuration — never from user input or project files — so there is no way for an imported project to direct the service at an arbitrary host.
- Import a Soroban/Stellar project (GitHub or archive upload). The import response carries detection metadata, and the project explorer's Stellar tab shows confidence, evidence, network hints, and relevant files.
- Run Stellar or Stellar Security analysis on the project. If the project is detected as Stellar/Soroban you get a grounded analysis; otherwise the tool says it is not applicable.
- Open Stellar in the navigation to inspect the configured network, an account (G…), or a contract (C…). Everything is read-only and bound to the configured network.
- From the command line:
flask stellar network
flask stellar validate G…
flask stellar account G…
flask stellar health
flask stellar contract C…For a step-by-step walkthrough of the whole developer flow (import a Soroban repository → see detection → run Stellar analysis → scaffold a contract), see docs/soroban-workflow.md.
The existing GitHub PR and issue AI analyses are detection-driven and Stellar-aware:
- When analyzing a pull request,
analyze_pull_requestruns the existing detection (detect_stellar_project) over the PR's changed files (filename/patch) plus a small, bounded slice of detection-relevant repository files (manifests, Stellar configs, contract layouts, CLI-tooling files). The repo slice is fetched through the user's own GitHub token and is capped, so nothing private or unbounded is pulled in. - When analyzing an issue,
analyze_issueruns the same detection over the same bounded repo slice. - If the evidence yields a Stellar/Soroban confidence of
possibleorlikely, a bounded, clearly-labelled Stellar context block (confidence, signals/evidence, network hints, relevant files, changed files) and Stellar-aware review guidance are appended to the prompt. The guidance covers authorization/access control, contract/admin authority, cross-contract calls, storage/TTL handling,panic!/unwrap!, network/config mistakes, secret/key exposure, and unsafe contract-state assumptions — restricted to what the diff/context actually supports. - If detection is
none(including plain Rust without Soroban evidence, or a repo that merely mentions "Stellar"), the existing generic PR/issue analysis runs unchanged with no Stellar instructions. - A failed detection never breaks the analysis: it falls back to the generic
path. No manual
stellar=trueflag exists — behaviour is always derived from detection.
No-fabrication policy: the Stellar guidance explicitly forbids claiming formal verification, deployed contracts, succeeded transactions, or live ledger/RPC state. PR/issue text and repository content are framed as untrusted data so they cannot redefine the system instructions. Authorization is unchanged: GitHub calls stay user-token-scoped and analysis never grants additional access.
- Point
STELLAR_NETWORK=customandSTELLAR_HORIZON_URL/STELLAR_RPC_URLat a localstellar-core/stellar-rpc(loopback only).
For tests and local development with no Stellar node and no external network, boot the deterministic offline mock:
from app.services.stellar_mock import MockStellarServer
server = MockStellarServer().start()
print(server.horizon_url, server.rpc_url) # -> http://127.0.0.1:<port>[/rpc]
# ...point a custom network config at server.horizon_url / server.rpc_url...
server.stop()or run it as a standalone process for manual local development:
python -m app.services.stellar_mockThe mock serves a fixed fixture set over the same two APIs the app reads:
Horizon-style JSON (/accounts/..., /transactions/..., /ledgers/...,
/assets) and the read-only Stellar RPC JSON-RPC method set on /rpc
(health, version, latest ledger, network, ledger entries, ledgers,
transactions, events, fee stats). It is read-only, deterministic, and never
touches a real network. In pytest it is available via the session-scoped
mock_stellar fixture; see tests/test_stellar_mock_network.py for an
end-to-end example driving the real StellarService and SorobanRpcClient.
- The test suite uses deterministic fixtures and mocked transport (including the in-process mock network); no real network access is required.
- Transaction signing/submission, wallets, or custodial features (out of scope by design — this is developer tooling).
- An account dashboard and a contract-data browsing UI (open contributor issues).
sendTransaction/simulateTransaction.
See CONTRIBUTING.md (Stellar/Soroban section) and
docs/soroban.md. Stellar work is tracked under the Phase 8
milestone with the stellar/soroban labels. Keep the SSRF guards, the
read-only invariant, and the honest-claims rule in mind on every change.