Skip to content

Architecture

This document is the canonical product and architecture stance for Caatinga. It complements package-level code and the CLI reference in docs/cli.md. Detailed rationale for selected decisions lives in Architecture Decision Records under docs/adr/.

One-sentence promise

Deployment Orchestration + Versioned Artifacts for Soroban: local, graph-aware deployment orchestration and portable, Git-versioned artifacts for TypeScript teams.

That does not mean hiding Stellar reality. Users keep a stable Caatinga surface (ctg build, ctg deploy, ctg generate, ctg invoke, @caatinga/client). Changes in flags, stdout, paths, transaction/XDR workflow, and subprocess composition are absorbed behind small adapters, not scattered across user scripts.

What Caatinga is (and is not)

Caatinga isCaatinga is not
Convention + orchestration + artifacts + frontend/client integrationA second Soroban/Stellar SDK
A thin CLI over @caatinga/coreA place to store private keys or run silent signing
Template-driven project scaffoldingA hosted registry required for core workflows (future registries are optional)

Primary competitor today: ad-hoc package.json scripts.

For a detailed breakdown of all features categorized into Core, Nice to Have, Experimental, and Out of Scope, refer to the Scope Policy.

Direct ecosystem overlap: Scaffold Stellar (stellar scaffold + stellar registry, official templates, environments.toml, Vite/React frontend).

Caatinga differentiation: npm-first TypeScript toolkit (@caatinga/cli, @caatinga/core, @caatinga/client), caatinga.config.ts + caatinga.artifacts.json as the per-network artifacts contract, CAATINGA_* error codes as a public API, explicit wallet adapters, and multi-contract orchestration via dependsOn — without an on-chain registry or Rust macro layer.

Caatinga vs Scaffold Stellar

DimensionCaatingaScaffold Stellar
Entry pointnpm install -g @caatinga/cliStellar CLI plugins (stellar scaffold, stellar registry)
Config contractcaatinga.config.ts + caatinga.artifacts.jsonenvironments.toml + registry naming
Deploy modelStellar CLI subprocess + per-network artifacts fileOn-chain registry publish/deploy workflow
Browser integration@caatinga/client with pluggable wallet adaptersGenerated TS clients + Vite/React template
Error surfaceStable CAATINGA_* codes for automationStellar CLI / plugin errors

What Caatinga should do unusually well: (1) persist git-versioned per-network deployment artifacts, (2) orchestrate multi-contract deploy graphs with dependsOn, (3) ship wallet-ready browser client integration, (4) track binding freshness, and (5) lower friction for JS/TS teams — CLI orchestration is infrastructure supporting those outcomes, not the headline value.

Competitive moat

MoatWhy it matters
Portable artifacts fileExit Caatinga without losing deploy history — caatinga.artifacts.json stays in your repo
CAATINGA_* error APIStable automation surface for CI/CD
Parser fixtures + adaptersAbsorb Stellar CLI stdout drift without user script churn
npm-first, no on-chain registrySovereignty for teams that reject mandatory registry workflows
Multi-contract DAG deployTopological deploy + ${contracts.*.contractId} placeholders

Honest risk: SDF may integrate overlapping workflow pieces into Stellar CLI or Scaffold Stellar. Caatinga competes on TypeScript DX + git artifacts + multi-contract orchestration, not on reimplementing Soroban or replacing the official SDK.

Core Pillars

Architecturally, Caatinga is structured around four pillars that compartmentalize responsibilities and prevent cross-boundary pollution:

1. Deployment (Orchestration Engine)

This pillar encompasses the build and deployment pipeline. It manages contract compilation (via Stellar CLI shell orchestration), multi-contract dependency topological sorting (dependsOn), placeholder resolution (e.g. ${contracts.token.contractId}), and executing post-deploy hooks (postDeploy). Components responsible: @caatinga/core (specifically deploy-graph, load-config), @caatinga/cli.

2. Artifacts (State Contract)

This pillar represents the static state representation of all deployments. The per-network caatinga.artifacts.json file serves as the Git-versioned contract between compilation, deployment, and client integration, capturing contract IDs, compiler hashes, and metadata. Components responsible: @caatinga/core (schema validations, state read/write).

3. Runtime (Client Integration Layer)

This pillar exposes the APIs consumed by browser/Node applications. It includes the TypeScript clients, pluggable wallet adapters, React context providers/hooks (@caatinga/client/react), and transaction pipeline orchestration (simulate → sign → submit → watch). Components responsible: @caatinga/client.

4. Automation (Developer Diagnostics & Safety)

This pillar ensures local workspace reliability, environment diagnostics (ctg doctor), regression checking (ctg smoke / postDeployRead), and CI/CD-friendly error APIs using stable error codes. Components responsible: @caatinga/cli (commands doctor, smoke), @caatinga/core (stable errors module).

Validation roadmap (flows)

  1. Supported v1 flow: init → build → deploy → generate → invoke plus @caatinga/client for browser-side binding/artifact/wallet interop.
  2. Shipped: multi-contract deploy with dependencies (e.g. deploy token, then a dependent contract such as vault that injects the token's contractId, then generate bindings for both, then invoke across that dependency). See ADR 0005.
  3. Shipped: upgrade / redeploy with artifacts historyctg deploy --upgrade (new instance) and ctg upgrade (in-place WASM replacement). See Contract upgrade.

Supported v1 flow diagram

Each box is either a file you commit, a CLI command you run, or a runtime component. The arrows show which inputs are required to start the next step — for example, deploy needs both the compiled WASM and the network configuration.

Package boundaries (monorepo)

  • @caatinga/cli (CLI Interface): argument parsing, terminal UX, and delegation to the core Orchestration Engine—no subprocess orchestration except through core APIs.
  • @caatinga/core (Orchestration Engine): load caatinga.config.ts, validate schemas, resolve networks/contracts, read/write caatinga.artifacts.json, run Stellar CLI and related tools via a single shell layer (run-command.ts). All execa usage stays here.
  • @caatinga/client (Integration SDK): browser contract client, Freighter adapter, SWK adapter, React context, and the transaction execution pipeline. No Node-only dependencies, no shell orchestration, no file-system access. It must remain bundling-safe (Vite, Webpack, Turbopack).
  • @caatinga/zk (ZK Cryptographic Engine): ZK proof serialization, Circom Groth16 workflow helpers, and browser binding args for on-chain verification.
  • packages/templates (Project Scaffolds): official template starter layouts consumed by ctg init.

For detailed package dependency boundaries and compliance rules, see Package Boundaries & Isolation Rules.

Deferred unless explicitly rescoped: CLI XDR commands, ctg generate --interop, full plugin system, RWA-only templates, visual dashboard, custom test runner as required core dependencies.

Dependency Map

Notes encoded in the diagram:

  • CLI Isolation: The CLI Interface depends on the Orchestration Engine (core), never the other way around.
  • Node vs Browser Boundaries: The Orchestration Engine is the only package that orchestrates subprocesses via CLI Adapters executing Stellar CLI commands. The Integration SDK (@caatinga/client) consumes only the browser-safe subpath @caatinga/core/browser, ensuring that Node-specific dependencies like execa or fs are never pulled into web applications.
  • State Registry: The Artifacts State (caatinga.artifacts.json) acts as the shared database between the Orchestration Engine (which writes it on deploy) and the Transaction Pipeline / Integration SDK (which reads it at runtime).

Meta-framework boundary: orchestrate workflow, not mental model

May abstract: build/deploy/bindings flow, artifact lookup, network config from the project, template layout, command composition, stable CLI commands, wallet adapter handoff, and generated-binding transaction workflow.

Should not hide (users and docs should keep these visible): contractId, network passphrase, RPC choice, accounts, wallet signing, XDR, fees, simulation, Soroban data model as understood via official SDKs and generated bindings.

Red flags (avoid): Caatinga-owned contract models, hand-rolled Soroban serialization, replacing generated bindings as the primary API, custom signing runtimes parallel to the Stellar ecosystem, or “smart” behavior that obscures what actually hit the network.

Rule of thumb: if Stellar CLI, stellar-sdk, Soroban SDK, or generated bindings already own it, Caatinga composes, validates, or organizes—it does not reimplement.

Product boundary: Caatinga ends at the typed client + resolved contract IDs (caatinga.artifacts.json, generated bindings, synced env). HTTP APIs, databases, async jobs, transaction hash persistence, and caller-specific auth models are application concerns — a green Caatinga pipeline does not imply a green production app. See production readiness and the app-side checklist in docs.

Source of truth (MVP)

Local project state is authoritative:

  • contracts/
  • Generated bindings (path from caatinga.config.ts)
  • caatinga.config.ts
  • caatinga.artifacts.json

Each generated binding package carries a .caatinga-bindings.json marker recording the source contractId, wasmHash, and network. ctg status, doctor, and generate compare the marker against caatinga.artifacts.json to flag stale bindings after a redeploy. The marker is a sidecar, not part of the artifacts schema: deleting a bindings directory simply resets its state to missing.

No central cache or remote artifact registry is assumed in the core MVP. Optional remote services may exist later but must not be hard dependencies of core.

ctg dev

MVP direction: opinionated proxy around Vite + Caatinga validation (not a plugin or template store). Official templates are Vite + React only (vite-react). Future adapters (next, astro, custom) are conceivable only after the core workflow and multi-contract story prove value. See CLI — Supported today vs not yet.

Extensibility

  • Templates: start as opinionated snapshots (react-vite-counter, etc.). Parameterized generators (--tailwind, wallet flavor, i18n) come later—they expand the test matrix quickly.
  • Template contract: every template includes a caatinga.template.json manifest (name, version, compatibleCore, paths) so templates and core semver are validated at init—see ADR 0003.
  • Post-deploy hooks: postDeploy, postDeployRead, and smoke are first-class config surfaces for wiring, read verification, and CI smoke — see ADR 0006 and Config — postDeploy. Expect DSL matchers (reachable, isArray, etc.) apply to hooks, ctg read --expect, and ctg smoke.
  • Verification layer: ctg smoke, ctg regression, and ctg ci run compose deploy/generate with read checks. @caatinga/core exports verifyExpect, evaluateEnvDrift, and runSmokeReads for custom tooling.
  • Plugins: still deferred for broader extension points (for example CI presets or indexer hooks). Keep hooks declarative and data-only until a concrete use case requires executable plugin code.

Ecosystem: official vs community templates

  • Official: live in the Caatinga repo, reviewed, CI-tested, semver-matrices documented.
  • Community: installable via Git URL or npm-style packages, never implicitly trusted—treat as untrusted code; warn users; avoid auto-running post-install scripts from external templates in MVP-class flows.

Distribution: MVP+1 favors Git + URL (e.g. ctg init my-app --template github:org/repo). A dedicated template registry is explicitly later—moderation, security, and availability cost.

Suggested naming: @caatinga/template-* for official; @scope/caatinga-template-* for community.

Networks vs environments

Today: artifacts keyed by network (same logical contract may differ per network—correct).

Future (MVP+1): environment (e.g. staging vs production) can share a network but differ in deployed contractIds. Expect either a new artifacts shape version or an explicit environments model—design TBD with migration (ctg migrate) when introduced.

Multi-contract

Deploy order is supported in core for declared dependencies (DAG / topological sort), with artifact-safe constructor arg injection through ${contracts.<name>.contractId} — see ADR 0005. The next layer is runtime wiring: ${source.address}, postDeploy, ctg wire, frontend env sync, and workspace builds are covered by ADR 0006.

CI and secrets

Caatinga does not manage long-lived private keys. CI provides identities (--source ci-deployer), secrets via the platform, and a configured Stellar CLI on the runner. Caatinga validates config, runs deploy/generate/invoke, updates artifacts, and fails with clear, stable error codes (see below).

Client and frontend SDK

@caatinga/client provides the browser/client-side interop layer: generated binding registration, artifact-based contractId lookup, wallet adapters, invoke(), read(), simulate(), buildXdr(), and explicit XDR/raw debug output. The @caatinga/client/react subpath ships WalletProvider + useWallet hooks so React apps stop hand-rolling wallet context — React stays an optional peer. Avoid a parallel generic Soroban client that bypasses generated types.

DX beyond CLI

Prefer ctg doctor (bins, config/artifact sanity, network/source checks, optional staleness hints later) before investing in VS Code/LSP.

Errors as public API

Stable CAATINGA_* codes are part of the contract for CI, support, and docs. New public errors must be added through the central CaatingaErrorCode object and documented in errors.md—see ADR 0004.

Testing strategy vs Stellar CLI drift

Layered approach:

  1. Unit tests in @caatinga/core.
  2. Fixtures of Stellar CLI stdout/stderr per supported CLI generation (parsing is the fragile boundary).
  3. Contract tests with pinned Stellar CLI versions in CI.
  4. Optional scheduled smoke against testnet.

The runtime compatibility check (evaluateStellarCliCompatibility) intentionally decouples the hard floor (22.x invoke-signing bug) from the last-tested version. Drift above the last-tested version is a non-fatal advisory, not a CI failure, so we can keep one pinned fixture version in CI while still running against whatever Stellar CLI the developer has installed. See the Stellar CLI version contract for the operational rules.

Versioning and migrations

Semver applies to monorepo packages and to serialized formats (caatinga.artifacts.json already has a version field). Breaking format or command behavior should eventually ship with ctg migrate—not required on day one, but fields and ADRs should assume migrations will exist.

Performance responsibilities

  • Rust / Stellar toolchain: real compile and WASM output.
  • Caatinga: detect stale WASM vs sources when feasible, avoid redundant generate, compare WASM hashes, emit clear “run build first” guidance. MVP: basic checks; later: stronger staleness and caching policies.

Business stance for the core

Core stays open-source and neutral (CLI, core, baseline templates, artifacts, config workflow). Revenue-bearing or hosted offerings, if any, stay outside the neutrality of the core dependency graph.


Architecture Decision Records

ADRStatusTopic
0001AcceptedStable Caatinga workflow while encapsulating Stellar CLI churn
0002AcceptedLocal artifacts and config as source of truth; no central registry in MVP
0003AcceptedTemplate manifest and core compatibility
0004AcceptedStable CAATINGA_* error codes and migration
0005AcceptedMulti-contract dependsOn and contractId injection

0001–0005 are ratified; multi-contract deploy sequencing and placeholder resolution are implemented in @caatinga/core and documented in ADR 0005.