Skip to content

opendecree/decree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

OpenDecree

OpenDecree

CI Release Go Reference Go Report Card License Project Status: WIP

Schema-driven business configuration management for multi-tenant services.

Alpha Software — OpenDecree is under active development. APIs, proto definitions, configuration formats, and behavior may change without notice between versions. Not recommended for production use yet.

OpenDecree quickstart demo: schema → config → watch

What is this?

OpenDecree manages business-oriented configuration — approval rules, fee structures, settlement windows, feature parameters — the kind of config that lives between your infrastructure settings and your application code.

How is this different?

Feature flag tools (LaunchDarkly, ConfigCat, Flagsmith) focus on boolean/multivariate flags for release management — not structured business configuration with schemas.

Infrastructure config tools (etcd, Consul, Spring Cloud Config) are low-level key-value stores without typed schemas, validation, or multi-tenancy.

Cloud config services (AWS AppConfig, Azure App Configuration) offer some validation but lack schema registries, gRPC APIs, real-time subscriptions, and are vendor-locked.

What makes OpenDecree unique:

No existing open-source tool combines a schema-first approach to typed configuration with native multi-tenancy, constraint validation, field-level locking, gRPC streaming, and versioned rollback — all in a single Go binary.

Features

  • Typed values — native proto types (integer, number, string, bool, timestamp, duration, url, json) with wire-level type safety
  • Schema validation — constraints (min/max, pattern, enum, JSON Schema) enforced on every write
  • Multi-tenancy — apply schemas to tenants with role-based access and field-level locking
  • Versioned configs — every change creates a version; rollback to any previous state
  • Real-time subscriptions — gRPC streaming pushes changes to consumers instantly
  • Audit trail — full history of who changed what, when, and why
  • Import/Export — portable schemas and configs in YAML format
  • Optimistic concurrency — safe read-modify-write with checksum validation
  • Null support — null and empty string are distinct values

SDKs

SDK Language Protocol Status Version Install
decree Go gRPC alpha Go release go get github.com/opendecree/decree/sdk/grpctransport@latest
decree-python Python gRPC alpha PyPI pip install opendecree
decree-typescript TypeScript gRPC alpha npm npm install @opendecree/sdk
REST API Any REST alpha curl

Go

The core SDK modules require Go 1.22+ and have zero external dependencies. The grpctransport module (default transport) requires Go 1.24+ because google.golang.org/grpc pins that version — if you need a Go 1.22-compatible transport, 👍 or comment on #90 to signal demand.

// configclient — application runtime reads and writes
client := grpctransport.NewConfigClient(conn, grpctransport.WithSubject("myapp"))
val, _ := client.GetInt(ctx, tenantID, "payments.retries")

// configwatcher — live typed values with auto-reconnect
w := grpctransport.NewWatcher(conn, tenantID, grpctransport.WithSubject("myapp"))
fee := w.Float("payments.fee", 0.01)
w.Start(ctx)
fmt.Println(fee.Get()) // always fresh
go get github.com/opendecree/decree/sdk/grpctransport@latest  # gRPC transport (pulls in configclient, etc.)
go get github.com/opendecree/decree/sdk/configclient@latest   # core client (no gRPC dependency)
go get github.com/opendecree/decree/sdk/adminclient@latest    # admin operations
go get github.com/opendecree/decree/sdk/configwatcher@latest  # live config watcher
go get github.com/opendecree/decree/sdk/tools@latest          # diff, docgen, validate, seed, dump

Go API docs on pkg.go.dev: grpctransport · configclient · adminclient · configwatcher · tools

Python

from opendecree import ConfigClient

with ConfigClient("localhost:9090", subject="myapp") as client:
    retries = client.get("tenant-id", "payments.retries", int)

    with client.watch("tenant-id") as watcher:
        fee = watcher.field("payments.fee", float, default=0.01)
        print(fee.value)  # always fresh

Docs: decree-python

TypeScript

import { ConfigClient } from "@opendecree/sdk";

const client = new ConfigClient("localhost:9090", { subject: "myapp" });
const retries = await client.get("tenant-id", "payments.retries", Number);

const watcher = client.watch("tenant-id");
const fee = watcher.field("payments.fee", Number, { default: 0.01 });
await watcher.start();
console.log(fee.value); // always fresh

Docs: decree-typescript

Examples

Runnable examples in examples/ — each is a standalone Go module you can copy into your own project.

Example What it shows
quickstart Connect and read typed values
feature-flags Live feature toggles with configwatcher
live-config HTTP server with hot-reloadable config
multi-tenant Same schema, different tenant values
optimistic-concurrency Safe concurrent updates with CAS
schema-lifecycle Create, publish, and manage schemas
environment-bootstrap Bootstrap from a single YAML file
config-validation Offline validation (no server needed)
cd examples && make setup   # start server + seed data
cd quickstart && go run .   # run any example

CLI

go install github.com/opendecree/decree/cmd/decree@latest

decree schema list
decree schema import --publish decree.schema.yaml  # import + auto-publish

decree tenant create --name acme --schema payroll-service --schema-version 1
decree config set acme payments.fee 0.5%          # use tenant name or UUID
decree config get-all acme
decree config versions acme
decree config rollback acme 2

decree watch acme                                  # live stream
decree lock set acme payments.currency             # lock field
decree audit query --tenant acme --since 24h

# Power tools
decree seed fixtures/billing.yaml                 # bootstrap from a fixture
decree dump acme > backup.yaml                    # full tenant backup
decree diff acme 1 2                              # diff two config versions
decree diff --old v1.yaml --new v2.yaml           # diff two files
decree docgen payroll-service                      # use schema name or UUID
decree validate --schema decree.schema.yaml --config decree.config.yaml

Global flags: --server, --subject, --role, --output table|json|yaml, --wait, --wait-timeout

Use --wait in Docker/Kubernetes init containers to wait for the server to be ready:

decree seed examples/seed.yaml --server decree:9090 --wait --wait-timeout 60s

Quick Start

Try it instantly (no Docker needed)

go install github.com/opendecree/decree/cmd/server@latest

# Start with in-memory storage — zero dependencies
STORAGE_BACKEND=memory HTTP_PORT=8080 decree-server

# Open http://localhost:8080/docs for Swagger UI
# All requests need x-subject header:
curl -H "x-subject: admin" http://localhost:8080/v1/schemas

Docker Compose (production-like)

git clone https://github.com/opendecree/decree.git
cd decree

# Start the full stack (PostgreSQL + Redis + migrations + service)
docker compose up -d --wait service

# gRPC at localhost:9090, REST/JSON at localhost:8080
# No JWT required — metadata auth is the default

REST API

The entire gRPC API is also available as REST/JSON (via grpc-gateway). Set HTTP_PORT to enable:

# Version check
curl http://localhost:8080/v1/version

# List schemas
curl -H "x-subject: admin" http://localhost:8080/v1/schemas

# Create a schema
curl -X POST http://localhost:8080/v1/schemas \
  -H "Content-Type: application/json" \
  -H "x-subject: admin" \
  -d '{"name":"payments","fields":[{"path":"fee","type":7}]}'

# Get config
curl -H "x-subject: admin" http://localhost:8080/v1/tenants/{id}/config

OpenAPI spec: docs/api/openapi.swagger.json

Using the CLI

# Set auth identity
export DECREE_SUBJECT=admin@example.com

# Create and publish a schema
decree schema import --publish examples/config-validation/decree.schema.yaml

# Create a tenant and set config
decree tenant create --name acme --schema <schema-id> --schema-version 1
decree config set <tenant-id> payments.fee "0.5%"
decree config get-all <tenant-id>

Architecture

flowchart LR
    subgraph Clients
        direction TB
        SDKs["🔧 SDKs\nGo · Python · TypeScript"]
        CLI[">_ CLI\ndecree"]
        UI["🖥️ Admin UI\ndecree-ui"]
        Direct["🔗 Direct\ncurl, custom"]
    end

    SDKs & CLI -->|gRPC| GW
    UI & Direct -->|REST| GW

    GW{{"🔐 Gateway\nauth · routing"}}

    subgraph Server["⚙️ OpenDecree"]
        SS["📋 SchemaService\nschemas, tenants"]
        CS["📝 ConfigService\nread, write, subscribe"]
        AS["📊 AuditService\nhistory, usage"]
    end

    GW --> SS & CS & AS

    subgraph Backends["💾 Pluggable Backends"]
        Storage[("Storage")]
        Cache[("Cache")]
        PubSub[("Pub/Sub")]
    end

    SS & CS & AS --> Storage
    CS --> Cache
    CS <--> PubSub
Loading

Single binary exposing three gRPC services + REST/JSON gateway. All external dependencies (storage, cache, pub/sub) are behind Go interfaces — swap implementations via STORAGE_BACKEND=memory for zero-dependency evaluation or testing. Deploy with ENABLE_SERVICES to control which services run on each instance.

Configuration

Server

Variable Description Default
GRPC_PORT gRPC listen port 9090
HTTP_PORT REST/JSON gateway port (disabled if empty) disabled
STORAGE_BACKEND postgres or memory postgres
DB_WRITE_URL PostgreSQL primary connection string required if postgres
DB_READ_URL PostgreSQL read replica connection string DB_WRITE_URL
REDIS_URL Redis connection string required if postgres
ENABLE_SERVICES Services to enable: schema, config, audit all
LOG_LEVEL debug, info, warn, error info

Authentication

JWT is opt-in. By default, the service uses metadata-based auth:

Variable Description Default
JWT_JWKS_URL JWKS endpoint — enables JWT validation disabled
JWT_ISSUER Expected JWT issuer optional

Without JWT, pass identity via gRPC metadata headers:

  • x-subject (required) — actor identity
  • x-rolesuperadmin (default), admin, or user
  • x-tenant-id — required for non-superadmin roles

Observability (all opt-in)

Variable Description
OTEL_ENABLED Master switch — initializes SDK + slog trace correlation
OTEL_TRACES_GRPC gRPC server spans
OTEL_TRACES_DB PostgreSQL query spans
OTEL_TRACES_REDIS Redis command spans
OTEL_METRICS_GRPC gRPC request count/latency
OTEL_METRICS_DB_POOL Connection pool gauges
OTEL_METRICS_CACHE Cache hit/miss counters
OTEL_METRICS_CONFIG Config write counter + version gauge
OTEL_METRICS_SCHEMA Schema publish counter

Standard OTel variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME) are respected by the SDK.

API

The API is defined in Protocol Buffers under proto/, published to BSR at buf.build/opendecree/decree. Three gRPC services:

  • SchemaService — create, version, and manage config schemas and tenants
  • ConfigService — read/write typed config values, subscribe to changes, version management
  • AuditService — query change history and usage statistics

Values use a TypedValue oneof — integer, number, string, bool, timestamp, duration, url, json — with null support.

All endpoints that accept a tenant or schema ID also accept the name slug — the server resolves automatically. Use UUIDs or human-readable names interchangeably:

Generate client stubs in any language from BSR, or use the official SDKs:

Repo Package
Go this repo github.com/opendecree/decree/sdk/*
Python decree-python opendecree
TypeScript decree-typescript @opendecree/sdk

Test Coverage

Coverage badges reflect business logic only — infrastructure wrappers that are tested at the integration/e2e level are excluded from the calculation:

Excluded Reason
store_pg.go PostgreSQL store implementations — thin DB wrappers, tested via e2e
redis.go Redis cache/pubsub implementations — thin wrappers, tested via e2e
storage/dbstore/ sqlc-generated query code
storage/postgres.go Interface definitions only
telemetry/ OpenTelemetry provider wiring boilerplate

Run ./scripts/coverage.sh to calculate the server coverage, or ./scripts/coverage.sh -v for a per-function breakdown.

Demos

Want to see OpenDecree in action without reading docs? The demos repo has self-contained, runnable examples — from a 5-minute quickstart to production patterns. Each demo runs with a single docker compose up.

Contributing

See CONTRIBUTING.md for development setup, build instructions, and contribution guidelines.

License

Apache License 2.0 — see LICENSE for details.

Packages

 
 
 

Contributors

Languages