Reaktor Graph Sources - bring existing systems into the graph

The Reaktor Living Graph is one logical, heterogeneous, nested port graph spanning definition, build, runtime and operations. Native composition and imported systems contribute facts to that same graph; source, service, runtime and delivery layers are projections, not separately authored architectures. Reaktor should not require a rewrite before it can understand an existing system.

If a product has a Python service, a Go gateway, a Spring monolith, and some Reaktor-native code, the desktop graph should still show the whole thing. The difference is what is known about each part, at which revision and scope, and which operations are applicable and authorized.

The rule is simple:

Provenance explains where a fact came from. Coverage explains what was examined. Neither grants authority or proves that an operation is applicable.

Source adapters can feed existing systems into the Reaktor graph, and the safety rules that keep the graph honest.

The Short Version

A graph source is anything that can describe part of a system to Reaktor.

For example:

  • a Reaktor app can describe itself directly;
  • an OpenAPI file can describe a service interface;
  • a source scanner can find handlers, classes, routes, and calls in Python or Go;
  • traces can show which services talk to each other at runtime.

Every fact that enters the graph must record its origin, meaning and limits:

QuestionWhy it matters
Where did this come from?Preserve the source artifact, extractor/version, evidence reference and derivation.
What does it establish?A declaration, desired binding, observed call and inferred relationship are different claims.
What was covered?Record revision, target, scopes/files/partitions, unsupported constructs, missing access and truncation.
What assurance supports it?Record schema checks, compiler resolution, tests or attestations for the exact claim and scope.
When does it apply?Record definition revision, activation/instance, source watermark, observation time and expiry/freshness policy.

These fields determine whether a fact can support a particular query or decision. Separately, an operation needs a supported executor, compatible target/state, current preconditions, principal authority, policy and a reviewed plan where required. A fresh trace can prove that one call occurred; it cannot prove complete topology. An old scan of an unchanged, pinned revision may still be valid for that revision.

The transport these sources feed, and the provenance a fact must carry when it crosses a runtime boundary, are specified in Reaktor Graph Protocol — native runtimes contribute over a live trunk, the other three source kinds contribute as overlays on the same model.

Current State

This is mostly a design today. A few useful pieces already exist:

PieceStatus
Desktop source navigationKotlin-oriented runtime source indexing exists; it is not a general multi-language semantic compiler.
Manual ServiceNode wrapperExists: projects typed service handlers and API objects into graph ports; HTTP clients and local server handlers are implemented.
Cloud inventory providersExist for config and cloud resources, not source code.
Unified graph provider modelDesigned, not implemented as a full registry yet.
Python/Go/JavaScript/Spring source scanningNot built.
Runtime service-map ingestionNot built.
Generated wrappers from OpenAPI or gRPCNot built.
Graph document editingImmutable GraphDocument commands and GraphEditorSession undo/redo exist; the document canvas entry point remains view-only.
Canonical graph commit and runtime activationNot implemented by the current editor commands, runtime connect or exports.

So this document is not claiming that foreign-code ingestion already ships. It defines the path from the pieces that do exist to the system Reaktor needs.

Four Ways A System Enters The Graph

Reaktor should label each claim by how it was learned. Several sources can describe the same logical element; they are coexisting evidence channels, not a four-level authority ladder.

Source kindPlain meaningExampleWhat it does not establish
NativeReaktor code describes its composition or contracts.A Kotlin or JS Reaktor node.Complete extraction, production health, hot-reload compatibility or permission to change it.
WrappedA service has an explicit Reaktor contract/proxy boundary.A Go payments API behind a reviewed client.Idempotency, safe retries, complete internals or authority to invoke/deploy it.
Source-scannedA scanner derives facts from pinned source files.Python routes, Spring controllers, Go handlers.Complete dynamic call resolution or a currently deployed runtime.
Runtime-observedA source records behavior in a specified runtime/time window.OpenTelemetry evidence of service A calling service B.Unexecuted paths, complete topology, source ownership or permission to inspect sensitive payloads.

The important safety rule:

No source kind grants actions automatically. Enable an operation only when its executor, applicability, preconditions, evidence requirements and authority are satisfied for the selected revision, environment and principal.

This prevents Reaktor from acting on guesses. Seeing a service in traces is useful. It is not enough evidence to rewrite, deploy, or delete anything. Conversely, a source-scanned service can have an authorized, verified deployment adapter without becoming Reaktor-native. A native node can remain inapplicable to hot reload because its target or state migration is unsupported.

How Existing Code Moves Toward Reaktor

Evidence and integration can accumulate around one logical service:

                  logical service identity
                 /        |         |       \
       source facts   interface   runtime   operation adapters
          revision     schema    instances   and contracts

A practical example:

  1. Reaktor sees a legacy billing service in traces.
  2. A source scanner links that service to BillingController.java.
  3. OpenAPI or gRPC reflection gives Reaktor a typed interface.
  4. Reaktor creates a ServiceNode wrapper around that interface.
  5. A new Reaktor-native implementation is built behind the same boundary.
  6. Traffic is compared between old and new implementations.
  7. An explicit cutover/removal plan retires the old implementation after the required compatibility, traffic and state-migration checks pass.

That is the point of graph sources: do not start with a rewrite. Start by making the existing system visible, then strengthen or replace boundaries where useful. Native conversion is optional; the product should remain operable with heterogeneous implementations.

What A Graph Source Emits

The exact Kotlin model belongs to the unified graph design. This is a proposed contract sketch, not current callable APIs:

interface SystemGraphProvider {
    val source: String
    suspend fun fragment(request: GraphSourceRequest): GraphFragment
}

data class GraphFragment(
    val sourceRevision: SourceRevision,
    val coverage: SourceCoverage,
    val claims: List<GraphClaim>,
    val operationDescriptors: List<OperationRef>,
)

data class SystemGraphNode(
    val id: String,
    val kind: String,
    val title: String,
    val sourceLocation: SourceLocation?,
    val provenance: List<Provenance>,
    val operations: List<OperationRef>,
)

For this page, the important fields are:

  • source: the importer, such as reaktor-native, openapi, otel, or source.python;
  • sourceLocation: the file and line to open when a user clicks the node;
  • provenance: evidence, extraction method, claim meaning, assurance and applicable revision/time;
  • coverage: what was examined, what is missing/unsupported, source watermarks and completeness for the requested domain;
  • operations: advertised operation descriptors, not credentials or a list of automatically permitted actions.

The graph registry reconciles facts through explicit stable IDs, artifact fingerprints and reviewed aliases. A billing API can have source locations, an OpenAPI schema, wrapper artifacts and observed runtime instances linked to one logical service. Do not merge merely by a similar name or URL, and do not merge a definition with its many activations. Conflicting claims remain visible with provenance; desired and observed values do not overwrite each other.

Exact queries require a specified snapshot vector across definition revision, activation epochs and participating source/index generations or watermarks, with complete coverage of the declared query domain. Missing source access, a cursor gap, truncation or stale dependent evidence yields a partial/unknown result. A vector alone does not prove a globally consistent cut across independently observed systems; the query must state the consistency guarantee it can establish. See visitor snapshot consistency.

Source Scanning

Source scanning is how Reaktor learns from non-Reaktor code without running it.

The first useful version does not need to solve every language perfectly. It should find the things developers expect to click:

  • files;
  • modules or packages;
  • classes;
  • functions;
  • routes and handlers;
  • service calls;
  • imports and dependencies.

The recommended implementation path:

  1. Use tree-sitter for fast syntax-level extraction across many languages.
  2. Add SCIP or CodeQL where compiler-grade references are needed.
  3. Emit one common graph shape instead of inventing one schema per language.
  4. Always attach sourceLocation so the desktop can open .py, .go, .java, .ts, or other files directly.

Source-scanned facts do not themselves authorize mutation. A scanner can be wrong and a call graph can be incomplete, so pin the source revision, extractor/schema version and coverage. A supported local refactoring tool may still propose an edit against those exact sources; compilation/tests and an authorized application path establish whether that edit is applicable. Scanned is provenance, not permanent read-only status.

Runtime Observation

Runtime observation is how Reaktor learns from a system that is already running.

The first runtime source should ingest OpenTelemetry service graph data:

  • services become nodes;
  • calls become edges;
  • latency, error rate, and request rate become useful node metadata.

Runtime observations are scoped and potentially delayed, sampled or incomplete. They show recorded paths, not every possible path. Preserve environment, activation, time window, sampling/coverage, watermarks and freshness. A missing edge cannot prove a dependency absent. Observations support dashboards, discovery, diagnosis and operation preconditions where the operation's contract accepts that evidence; they do not grant authority.

OpenAPI and gRPC reflection are slightly different. They do not show source, but they can recover a typed interface. That interface is what lets a runtime-only element gain a reviewed wrapper. Reflection results also need target/version and access provenance; they are not automatically the complete contract of every deployed instance.

Wrapping

Wrapping gives a non-Reaktor service an explicit, inspectable integration boundary.

The wrapper is a Reaktor ServiceNode proxy in front of the real service. The foreign service keeps running as-is, but calls pass through a Reaktor boundary. The proposed policy layer can add, where the underlying operation supports it:

  • retries;
  • timeouts;
  • circuit breaking;
  • auth context propagation;
  • telemetry;
  • permission checks.

The wrapper should contain translation and safety logic, not business logic.

These are policy possibilities, not guarantees implied by ServiceNode. Retrying an effectful request requires an idempotency/deduplication contract; a timeout does not prove the server stopped; a circuit breaker does not make a call durable. Record transport, request/result schema versions, authority propagation, cancellation, ordering, stream demand and delivery semantics on the boundary. Local, HTTP and durable-message realizations are interchangeable only when they satisfy the caller's declared requirements.

Today, this exists manually. The design goal is to generate much of it from OpenAPI or gRPC reflection, then let a developer review and finish the wrapper.

What Actions Should Be Allowed

The desktop evaluates each operation independently. It should explain an unavailable action using its actual missing applicability or authority condition, rather than a provenance tier.

Operation familyConditions to evaluate
Inspect/open source/dashboardAuthorized visibility, exact object/source binding and sensitivity policy; read operations can have effects or expose sensitive data.
Edit/refactorSupported source or definition editor, base revision, applicable transform, validated patch and authorized destination.
Invoke/queryRegistered executor, compatible operation schema, current target, principal authority and effect/data policy.
Deploy/restart/submitVerified artifact/environment mapping, supported provider adapter, current preconditions, scoped authority and a fingerprinted execution plan.
Hot reload/runtime rerouteCompatible implementation/ABI, explicit activation support, state and in-flight-work plan, target/platform constraints and required authority.

Enforce this in the shared executor and expose the same decision to humans and agents. A file path or native label must not unlock deploy/destructive actions. A separately verified deployment adapter can make a deploy applicable to foreign code. Definitions commit through typed patches; runtime and external effects execute through plans and produce receipts. A graph commit is not proof that an environment activated it.

Implementation Plan

Build this in small steps:

StepDeliverableWhy first
1Establish source revision/coverage contracts and per-operation applicability/authority checks; generalize source navigation to any supported file:line.Makes imported facts useful without granting ambient actions.
2Implement the graph provider registry, identity reconciliation and snapshot vectors.Lets many sources describe one service without collapsing definitions, activations or conflicting claims.
3Add one or two source scanners, likely Python and Go.Proves non-Reaktor code can appear in the desktop.
4Add OpenTelemetry service-map ingestion.Shows live topology for systems without source access.
5Generate reviewed ServiceNode wrappers from OpenAPI or gRPC.Gives existing services safe Reaktor powers.
6Integrate operation plans/receipts, source-change invalidation and gap recovery with the shared executor.Keeps decisions valid across source changes and runtime epochs.
7Add a Reaktor-native definition manifest with stable identities and source maps.Makes native composition precise and gives refactors a diffable artifact without claiming arbitrary Kotlin is statically recoverable.

The first real milestone should be modest:

Click a Python or Go node in Reaktor Desktop and jump to the exact source file, with pinned source revision, extractor and coverage visible, and only applicable, authorized actions enabled.

That would prove the model without pretending the whole migration system exists.

What Happened To Graphify

graphify is not the right shape anymore.

The old idea assumed the useful graph already existed inside Reaktor. Existing systems break that assumption. A real product has code, services, configs, interfaces, and traces that Reaktor did not create.

So graph sources replace graphify:

  • preserve provenance, assurance and coverage as separate dimensions;
  • keep the idea of graph reports and graph diffs;
  • add source scanning, runtime observation, and service wrapping;
  • feed everything into the unified system graph instead of a separate graph.

reaktor-compiler can still matter here. Its future role should be native Reaktor extraction: produce a stable definition manifest and source maps, then diff that artifact during refactors. Kotlin DSL authoring remains fully expressive; evaluated manifests must capture inputs, bounds and provenance. Dynamic or effectful construction that cannot be recovered statically must be represented explicitly or evaluated in a controlled authoring environment, not guessed by a scanner. Runtime-created instances link back to declared factories and activation epochs.

Open Decisions

  • Which two languages should the first source scanners support?
  • Which coverage/assurance vocabulary can be shared by extractors without collapsing source origin into a trust score?
  • How much wrapper code should be generated versus hand-written?
  • What is the minimum source graph that is useful in the desktop?
  • Which preconditions, evidence scopes and authority checks does each operation require, and which sources can establish them?

See Also

  • Unified Graph - Use before building Reaktor Engine graph importers, cloud/resource nodes, operation providers, or MCP graph tools.
  • Graph Visitors - Use before designing a new graph pass or selector.
  • Capability Runtime - Use before branching behavior by platform, device, network, permission, or renderer state.
  • Service Layer - Use before adding service APIs, splitting reaktor-service out of reaktor-graph, wiring handlers to Spring/Workers, or making modules graph-projectable without hard graph dependencies.
  • Security Plan - Use before enabling deploy actions, remote agents, or privileged commands.
  • Visual Language - Use when designing the node-based authoring/orchestration language and its editor, compiler, and agentic surface.