Ramen is the stateful reconciliation engine that turns API-source-backed desired resources into deterministic, reviewable UWS plans. It records local SQLite state and history, then hands only approved action documents to an explicit trusted executor boundary.
The native source of truth is a UWS project plus Ramen metadata for identity, lifecycle, operation roles, hashes, state matching, and redaction. OpenAPI, AWS Smithy JSON, and Google Discovery describe the available operations. Terraform/OpenTofu and Ansible conversion plus AI-assisted authoring are optional on-ramps into that native model, not alternative runtimes.
Ramen is for teams that have API source documents and need desired-state workflows without centering the system on provider plugins, backend compatibility, module download, or Terraform/OpenTofu plan files. Typical adopters include API platform teams, internal developer platform teams, operators managing APIs without mature providers, teams migrating HCL-shaped declarations, and UWS/OpenUdon users who need stateful reconciliation around workflow documents.
Ramen differs from adjacent tools in a narrow way:
- Terraform/OpenTofu are provider-backed infrastructure runtimes; Ramen is an API-source reconciliation engine with HCL conversion as an adapter.
- Generic workflow runners execute steps; Ramen adds identity matching, dependency graphs, deterministic plans, import, refresh evidence, state history, and approval-artifact checks.
- Generated SDKs and CLIs such as
azandgcloudprovide imperative API calls; Ramen provides operator workflows and durable desired-state records.
Community users should be able to evaluate Ramen locally through native project
examples, mock execution, readable plans, stable diagnostics, clear non-goals,
and ramen convert for HCL migration. Enterprise users should look for
approval artifacts, redacted SQLite state history, reproducible plans, explicit
trusted executor boundaries, no credential value storage, and future policy
integration points.
Ready in v0.1: provider-free native validation, graphing and planning; local state history; digest-bound approval artifacts; mock-backed apply and refresh; read-only state inspection; a supported in-process executor contract; and a credential-free native example.
Experimental before v1: broader resource mappings, live executor adapters, policy integrations, authoring and conversion adapters, imperative runbooks, and parameterization ergonomics. See SUPPORT.md and the compatibility contract for the exact boundary.
See docs/evidence-index.md for the current credential-free, recorded replay, and sanitized live evidence that backs these claims.
Install the CLI with Go:
go install github.com/OpenUdon/ramen/cmd/ramen@v0.1.0
ramen version --jsonNative UWS 1.9.1 JSON, YAML, and HCL projects may carry an optional
contentTrust registry. ramen validate preserves that registry and runs the
UWS advisory data-flow analyzer only when it is present. Findings have stable
codes, document paths, and fixed messages; default validation reports them as
warnings and remains valid. The existing explicit --strict flag promotes all
warnings to errors. Ramen supplies Browsertools' resolver for contained
browser-profile sources; other extension-owned flow remains unknown or
opaque unless UWS core can recover it directly. Analysis does not plan,
approve, apply, run, touch state, authorize an executor, or inspect runtime
values.
Linux, macOS, and Windows archives for amd64 and arm64 are attached to the
GitHub v0.1.0 release with a SHA256SUMS file. Ramen requires the Go version
declared in go.mod when used as a library.
The local widget example uses only a checked-in OpenAPI document and the mock executor. It performs no network calls and needs no credentials:
ramen init \
--project ./examples/widget \
--state /tmp/ramen-widget-state.db
ramen validate --project ./examples/widget
ramen graph --project ./examples/widget
ramen plan \
--project ./examples/widget \
--state /tmp/ramen-widget-state.db \
--out /tmp/ramen-widget-plan.json
ramen apply \
--plan /tmp/ramen-widget-plan.json \
--state /tmp/ramen-widget-state.db \
--auto-approve \
--mock \
--out /tmp/ramen-widget-apply
ramen state list --state /tmp/ramen-widget-state.dbSee examples/widget for the project, API source, and annotated workflow.
The credential-free browser example demonstrates native UWS 1.9/browser 1.7 desired state, authentication 1.1, popup/frame contracts, scalar outputs, symbolic credentials and sessions, and mock-only handoff. See Browser Desired State for the exact version, approval, and runtime boundary.
The native desired-state lifecycle is:
ramen init
ramen validate --project DIR --json
ramen graph --project DIR --format json
ramen plan --project DIR --target ADDRESS --exclude ADDRESS --replace ADDRESS
ramen plan --project DIR --out plan.json
ramen apply --plan plan.json --auto-approve --mock
ramen refresh --mock
ramen import
ramen show plan.json
ramen state list
ramen force-unlock LOCK_HOLDER --state PATH
ramen version --jsonExperimental on-ramps create or convert native artifacts:
ramen author --context context.json --goal "Manage widgets"
ramen icot --goal "List resources" --openapi api=api.json --network ask --no-llm --validate --graph
ramen convert
ramen convert ansible --playbook playbook.yml --argspec-dir argspecs --inventory inventory.yml --extra-var env=prodSee the shared static conversion contract, the Terraform/OpenTofu conversion contract, and the Ansible conversion contract for their modes, reports, static inputs, Ramen-owned metadata, validation, artifacts, and compatibility boundaries. The client-language conversion model provides the unified ownership/evidence matrix and syntax-promotion rule.
Terraform conversion can also accept repeatable
--provider-schema ID=PATH snapshots for offline client-configuration
validation. This never runs a provider and does not replace the required API
source that defines server operations.
Ansible conversion can resolve bounded regular INI/YAML/JSON inventory files
for all, one exact host, or one exact group and apply literal extra vars at
the highest static precedence. This chooses client-requested host facts only;
Ramen still never opens an inventory connection, SSH session, or module runtime,
and inline extra-var values are redacted from conversion reports. Empty host
selections and credential-shaped non-runtime inventory or nested extra-variable
keys fail closed. Simple default-private include_role remains lowerable only
when its role has no non-empty defaults or vars.
ramen run is an adjacent imperative UWS runbook command; it does not create
desired-state resources. Default release builds include mock execution only.
Platform teams integrate a trusted runtime through the supported
executor.Executor
interface. ramen version --json reports local build metadata without network
checks or telemetry.
ramen icot uses a dependency-aware v2 interview. It inspects repeatable
--api-source KIND:ID=PATH, --openapi ID=PATH, and --source-root PATH
inputs before asking questions; supports OpenAPI/Swagger, Google Discovery,
AWS Smithy, AsyncAPI, GraphQL, OpenRPC, gRPC/protobuf, and OData; and shows all
currently ready decisions as one round. --prompt-mode full|normal|fast
controls safe defaults, while forced or uncertain decisions are always shown.
Broad goals must select one active workflow; later workflows remain
non-executable candidates in the generated project.
ramen author and ramen icot consume
authoring.prompt-context.v2. API authentication remains an outer OR of inner
AND symbolic binding sets, including explicit anonymous alternatives. When an
operation offers more than one set, iCoT forces one numbered, resume-safe
selection before request mappings; direct authoring and static conversion fail
closed instead of unioning credentials. Prompt-context v1 is rejected.
Remote source lookup is separate and bounded by --network never|ask|allow.
Interactive mode defaults to ask; agent mode is effectively never unless
allow is explicit. No project or selected source is written until the full
proposal is approved. Structured technical deferrals can save a non-runnable
draft and resumable v2 session; default interview state stays under
OUT/.icot/, and --resume SESSION reopens deferred leaves for promotion.
--agent and --print never write deliverables.
Start from a local Azure Resource Manager OpenAPI file and draft a read-only project:
go run ./cmd/ramen icot \
--goal "List Azure resources in the selected subscription" \
--api-source openapi:azure-resources=../<azure-resources>/resources.json \
--out ./.ramen/azure-read \
--no-transcript \
--validate \
--graphChoose Resources_List if prompted for an operation ID. Then plan the read
without embedding credentials in the project:
go run ./cmd/ramen plan \
--project ./.ramen/azure-read \
--action read \
--var azure_subscription_id="<subscription-id>" \
--out ./.ramen/azure-read/read-plan.jsonMock execution path:
go run ./cmd/ramen apply \
--plan ./.ramen/azure-read/read-plan.json \
--var azure_subscription_id="<subscription-id>" \
--auto-approve \
--mock \
--out ./.ramen/azure-read/mock-applyLive Azure reads require a short-lived access token supplied through the operator environment:
UDON_CREDENTIAL_AZURE_AUTH="$(az account get-access-token \ --resource https://management.azure.com/ \ --query accessToken \ -o tsv)" \
go run -tags udon ./cmd/ramen apply \
--plan ./.ramen/azure-read/read-plan.json \
--var azure_subscription_id="<subscription-id>" \
--auto-approve \
--executor udon \
--udon-output ./.ramen/azure-read/udon \
--out ./.ramen/azure-read/applyExample placeholders only: <subscription-id>, <resource-group>, <server>, <database>.
Do not copy real IDs/tokens into tracked artifacts.
Do not commit .ramen/ state, live response payloads, subscription IDs,
tenant IDs, client IDs, secrets, or access tokens. Mutating Azure examples
should use disposable resources, explicit scoped permissions, tags, cost
guardrails, and a verified cleanup command.
GOWORK=off go mod download
GOWORK=off go test ./... -count=1 -timeout=10m
GOWORK=off go vet ./...
git diff --checkThe canonical memory bank is tracked under ../tofu/ramen in a sibling
development checkout, but public builds and tests do not require that checkout.
Optional udon adapter check when the private sibling checkout is available:
go test -tags udon ./...