Skip to main content

IFURI Digital Twin Lab 0.4

AI Cost Tracking

PyPI Version Python License AI Cost Human Time Model

  • 🤖 LLM usage: $1.0921 (6 commits)
  • 👤 Human dev: ~$363 (3.6h @ $100/h, 30min dedup)

Generated on 2026-08-08 using openrouter/qwen/qwen3-coder-next


A reference implementation for building software from user intent and external Markdown sources while keeping the LLM behind a strict DSL-only boundary.

Project Integrity Closure v2

onlyDSL now acts as a control plane above the external twin-dsl engine. It consumes live ProjectIntegrityDSL, verifies its exact append-only iteration version, derives a RepairPlanDSL from a system-owned process registry, projects AQL authority and requires TestQL/EQL closure evidence. It does not implement CAD or execute model-supplied commands.

The six new contracts are SpatialClassDSL, AssumptionDSL, ParameterContractDSL, EvidenceSetDSL, AuthorityProjectionDSL and RepairPlanDSL. See Project Integrity Closure v2.

Core architecture

user sentences
  -> runtime SourceDSL
  -> IFURI capability
  -> LLM Gateway
  -> DigitalTwinDSL revision 1

sources/*.md
  -> deterministic Markdown compiler
  -> SourceIndexDSL + SHA-256 provenance
  -> IFURI capability
  -> LLM Gateway
  -> validated DigitalTwinDSL revision N+1
  -> BuildPlanDSL
  -> future code-builder capability

The wider runtime retains the previous architecture:

  • logical ifuri://... capability addresses instead of host:port identities,
  • Protobuf IfEnvelope as a transport-neutral wire contract,
  • CQRS + Event Sourcing,
  • PostgreSQL as the authoritative event store,
  • transactional outbox,
  • NATS Core for request/reply and JetStream for durable delivery/replay,
  • no gRPC foundation dependency,
  • Python/Node/PHP IFURI parity tests.

Why OPENROUTER_API_KEY exists now

Version 0.3 had a generic LLM_API_KEY but no first-class OpenRouter provider. Version 0.4 adds a dedicated provider configuration and a Docker smoke profile.

Create .env:

cp .env.example .env

Then edit:

LLM_BACKEND=openrouter
OPENROUTER_API_KEY=sk-or-...
OPENROUTER_MODEL=~openai/gpt-latest
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_HTTP_REFERER=http://localhost:8787
OPENROUTER_APP_TITLE=IFURI Digital Twin Lab

Do not commit the real key. .env is excluded by .dockerignore.

OpenRouter's official quickstart uses https://openrouter.ai/api/v1/chat/completions, Bearer authentication, and currently documents ~openai/gpt-latest as a latest-model alias. HTTP-Referer and X-OpenRouter-Title are optional attribution headers.

Official references:

Quick test without spending API credits

The deterministic demo backend exercises the complete architecture without a network LLM:

python3 -m unittest discover -s tests -v
python3 server.py

Open:

http://localhost:8787

Workflow in the UI:

  1. Enter a few sentences describing the application you want.
  2. Click Bootstrap twin.
  3. Inspect generated TwinDSL and the rendered Mermaid SVG; the highlighted Mermaid source remains available in a collapsible detail view.
  4. Put Markdown files under sources/.
  5. Click Scan sources/.
  6. Click Update twin.
  7. Verify that the revision increments while INTENT_FINGERPRINT stays unchanged.
  8. Click Generate plan to produce BuildPlanDSL.

Real OpenRouter test

With a valid key in .env:

docker compose up -d nats postgres app

Then use the web UI, or run the isolated real-LLM smoke test:

docker compose --profile llm run --rm openrouter-smoke

The smoke test performs three actual LLM stages through the same IFURI gateway used by the application:

SourceDSL -> ifuri://llm/twin/default/commands/bootstrap -> TwinDSL r1
TwinDSL + SourceIndexDSL -> ifuri://llm/twin/default/commands/update -> TwinDSL r2
TwinDSL r2 -> ifuri://llm/builder/default/commands/plan -> BuildPlanDSL

If OPENROUTER_API_KEY is missing, the smoke script exits without making a paid request.

sources/ design

Markdown is not concatenated directly into a prompt. source_ingest.py creates a deterministic representation:

SOURCE_INDEX markdown_sources
DOC source_1_architecture
  PATH "sources/architecture.md"
  SHA256 sha256:...
  HEADING 1 "Architecture"
  PARAGRAPH "..."
  BULLET "..."
  CODE python HASH sha256:... CONTENT "..."
END
END_SOURCE_INDEX

This means the LLM receives a typed source document with provenance rather than raw Markdown formatting.

Limits can be configured:

SOURCE_MAX_FILES=64
SOURCE_MAX_CHARS=120000

DigitalTwinDSL

The twin is an application model rather than generated source code. It records:

  • immutable user intent fingerprint,
  • current goals,
  • nodes/services/actors/models,
  • logical IFURI capabilities,
  • graph edges,
  • invariants,
  • allowed/required/forbidden evolution,
  • source references and hashes,
  • open questions.

Example shape:

TWIN application
VERSION 1
REVISION 2
INTENT_FINGERPRINT sha256:...
INTENT_SUMMARY "..."
GOAL "..."

NODE digital_twin KIND model
  RESPONSIBILITY "Maintains the current source-backed application model."
  EVIDENCE user_intent
  EVIDENCE source_1_architecture
END

CAPABILITY update_from_sources
  URI ifuri://llm/twin/default/commands/update
  OWNER digital_twin
  INPUT ifuri.v1.DslDocument
  OUTPUT ifuri.v1.DslDocument
  RESPONSIBILITY "Refine the twin without replacing original intent."
END

INVARIANT preserve_user_intent
  ASSERT "Every revision keeps the original INTENT_FINGERPRINT."
  EVIDENCE user_intent
END

EVOLUTION
  ALLOW "Refine implementation details supported by sources."
  REQUIRE "Preserve user intent."
  FORBID "Invent unsupported product requirements."
END

SOURCE user_intent HASH sha256:...
SOURCE source_1_architecture HASH sha256:... PATH "sources/architecture.md"
END_TWIN

Intent versus evidence

The design deliberately separates three things:

user intent       = what the product is supposed to achieve
source evidence   = facts/constraints that may refine how it should work
implementation    = code produced from the validated current twin

A source cannot replace the user's original intent. The runtime enforces this by keeping INTENT_FINGERPRINT immutable between revisions and by refusing a TwinDSL update that removes existing invariants or invents unknown source identifiers.

Unsupported information should remain an OPEN_QUESTION instead of silently becoming a requirement.

Fail-closed LLM repair

A provider can still produce invalid output. Version 0.4 therefore uses a repair loop:

LLM output
 -> BoundaryGate
 -> TwinDSL parser/semantic validator
 -> reject if invalid
 -> original trusted DSL bundle + ValidationDSL errors
 -> retry

The rejected raw model response is never copied into the next prompt.

Configure retries with:

LLM_REPAIR_ATTEMPTS=2

API

Provider status

GET /api/llm/status

The API reports only whether a key is present; it never returns the key value.

Bootstrap the twin

POST /api/twin/bootstrap
Content-Type: application/json

{
  "intent": "Build an application ...",
  "reset": true
}

Scan sources

GET /api/twin/sources

Update the twin

POST /api/twin/update
Content-Type: application/json

{}

Build plan

POST /api/twin/plan
Content-Type: application/json

{}

Current twin

GET /api/twin

Persistent state

The current twin is stored under:

state/digital_twin.md

Each accepted revision is also written to:

state/history/rev-XXXX-<timestamp>.md

Docker mounts ./state:/app/state so accepted revisions survive container restarts.

Docker integration suite

The integration service exercises:

  • real NATS request/reply,
  • JetStream stream/replay,
  • PostgreSQL authoritative Event Store,
  • transactional outbox,
  • Protobuf envelopes,
  • DSL-only ContextDSL → IntentDSL path,
  • DigitalTwinDSL bootstrap,
  • sources/ update to revision 2,
  • BuildPlanDSL generation.

Run:

docker compose build
docker compose run --rm integration

Guarded autonomous evolution

The optional evolution profile records runtime guidance/incidents as DSL and uses the Subactor operational layering model: the LLM proposes only PatchDSL; a system-owned aql:contract/v1 authorizes OQL plus exact URI Process routes; DOQL/EQL remain read-only; a hash-bound Process Envelope and independent receipt precede success. A one-shot TestQL service verifies onlyDSL and the live Digital Twin after startup, persists TestQLDSL, and routes failures into the appropriate next evolution cycle. Dependencies, Docker, runtime and the evolution implementation are governable through explicit AQL grants. Secret values never reach the model, and model-supplied commands are never executed.

Start in recording-only mode:

LOCAL_UID="$(id -u)" LOCAL_GID="$(id -g)" EVOLUTION_MODE=observe \
docker compose --profile evolution up -d --build live-app evolution-agent

After reviewing the policy, enable guarded application with EVOLUTION_MODE=apply. See docs/AUTONOMOUS_EVOLUTION.md for the operating procedure, APIs, state layout and rollback rules.

Tests

Local suite:

python3 -m unittest discover -s tests -v

The local suite currently contains 73 tests covering packaging and architecture invariants, IFURI, Protobuf, Event Sourcing/outbox, NATS wire protocol, multi-runtime URI parity, ContextDSL, IntentDSL, TwinDSL, source ingestion, OpenRouter, TestQL, the embedded dashboard, deterministic diagnostics, AQL/URI authorization, process envelopes, guarded rollback and the complete ProjectIntegrity → RepairPlan → TestQL/EQL closure cycle.

The browser detects and highlights JSON, JSONL, Mermaid and the project DSL family. Runtime values are HTML-escaped before token markup is added. Mermaid is rendered with its strict security profile; if the CDN renderer is unavailable, the highlighted source and an explicit error remain visible.

See TEST_REPORT.md for the exact execution status of the delivered package.

License

Licensed under Apache-2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

onlydsl-0.0.6.tar.gz (103.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

onlydsl-0.0.6-py3-none-any.whl (101.1 kB view details)

Uploaded Python 3

File details

Details for the file onlydsl-0.0.6.tar.gz.

File metadata

  • Download URL: onlydsl-0.0.6.tar.gz
  • Upload date:
  • Size: 103.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for onlydsl-0.0.6.tar.gz
Algorithm Hash digest
SHA256 a8c041f9ed8aecad436de8c142b3c73513eed21f8d7a003fa274adf6a6c14bee
MD5 0021e0b7fd51e7cf4475d11b6a743711
BLAKE2b-256 a9ac9648955a60cfd870563497206d5d95ed601044dd8b4f582a2649a1fcc5bf

See more details on using hashes here.

File details

Details for the file onlydsl-0.0.6-py3-none-any.whl.

File metadata

  • Download URL: onlydsl-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 101.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for onlydsl-0.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 2e596a98567338f707b886e68f7d7ec0c872ec9d3905eee5d674a80a959795b0
MD5 4699d689f40962fb03e692378a584610
BLAKE2b-256 e52f1d09bbeeab2fb3d764f6214a9f9c333f3152efdb61dbede1f9453f8b8f3d

See more details on using hashes here.

Release history Release notifications | RSS feed

0.0.13

2 files

0.0.12

2 files

0.0.11

2 files

0.0.10

2 files

0.0.8

2 files

0.0.7

2 files

This release

0.0.6 This release

2 files

0.0.5

2 files

0.0.4

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page