Skip to main content

Yian - The Agent Composer

Documentation

Yian is a small language and runtime for readable agent flows. You author a fixed graph in Docker-Compose-shaped YAML; the framework infers data dependencies, applies explicit ordering constraints, validates types, and runs through an append-only log.

In this framework, an agent is a composable transformation from a named input record to an output value. It can be represented by one node, a flow of nodes, or a child flow used inside another flow. The YAML AGENT node (kind: agent) is one concrete implementation: an LLM-backed node with a task prompt and optional tool grants, model configuration, and long-term memory.

The author fixes the graph. LLMs generate values and may choose among explicitly granted tools, but they do not rewrite the flow structure at run time.

# hello.yaml — a compact one-node flow
id: hello
name: hello
input:
  name: str
output: str
kind: agent
prompt: Write a warm one-sentence greeting to ${name}.
yian run hello.yaml --input name=Ada --provider ollama --model llama3.2:3b

See Agent for the conceptual model and Flow syntax for the complete YAML surface. AGENT nodes can declare typed local variables with validated defaults and reference them in prompts as ${name}.

Why fixed flows?

  • Readable: the flow is the plan. Humans and models can inspect the same artifact before it runs.
  • Composable: typed nodes build flows; CALL, MAP, and LOOP apply child flows recursively within the runtime depth limit.
  • Predictable: data references determine the data edges, and the LLM never changes the authored call graph.
  • Recoverable: every accepted transition is appended before it is applied, so an interrupted run can replay a validated record prefix.
  • Evolvable: fixed flow and node identities give learning stable targets, so recorded outcomes from completed runs can improve later behavior without mutating the graph mid-run.

Install

Early stage. Yian is under active development. The API, YAML surface, and CLI may change quickly.

The current documentation describes the main branch. PyPI release 0.0.1 contains an older, incompatible package, so install the current version from a clone until the next release:

git clone https://github.com/ngocbh/yian.git
cd yian
python -m pip install ".[all]"

For development, use python -m pip install -e ".[all,dev]" instead.

Provider extras can be installed separately: anthropic, openai, google, or ollama. The core engine and CLI do not require a provider SDK; a flow needs one only when it contains an AGENT node.

Connect OpenAI with yian auth openai, choose ChatGPT subscription sign-in or an API key, and select a default model. Both methods use provider: openai with Yian's ordinary tools and memory. OpenAI is the default provider; successful setup saves your chosen model for subsequent runs. See authentication setup.

Run a flow

yian run FLOW.yaml [--inputs inputs.json] [--input k=v]... \
  [--provider P] [--model M] [-w N] [--log PATH]

--inputs accepts a JSON object, including lists, records, and explicit nulls. Repeatable --input k=v supplies scalar overrides. In a terminal, the CLI prompts for declared inputs that are still missing.

New runs use up to eight workers for independent ready nodes. Set --num-workers N / -w N to override the count, or -w 0 for serial execution. Resuming without a worker flag preserves the count recorded in the run log.

The CLI reports its selected JSONL path before execution. Once runtime initialization commits RunStarted, that file is the authoritative log. The default is ~/.yian/runs/<run_id>.jsonl; choose another new path with --log. Resume an interrupted run against the same flow:

yian run FLOW.yaml --resume PATH

Run logs can contain inputs, model/tool/human data, outputs, memory snapshots, configuration, and tracebacks. Treat them as sensitive. See The yian CLI for input behavior, diagnostics, concurrency, and recovery.

For an interactive flow-backed chat:

yian chat [FLOW] [--workspace DIR] [--provider P] [--model M]

The default yian chat can inspect, validate, run, and—after explicit approval—write flows inside its workspace. A supplied chat flow owns its own typed exit behavior.

Use the Python API

from pathlib import Path

from yian import load_flow, run_flow

path = Path("hello.yaml")
flow = load_flow(
    path.read_text(),
    search_paths=[path.parent],
    source_label=path.name,
)
result = run_flow(
    flow,
    {"name": "Ada"},
    llm_config={"provider": "ollama", "model": "llama3.2:3b"},
)
print(result.status, result.output)

load_flow parses, validates, and compiles the YAML into a reusable ComposedFlow. run_flow makes a private graph for one run and returns a RunResult with either the flow output or an expected Failure. Host, control, log, and invariant faults propagate as exceptions.

A library host can inject per-run tools (including its ask_user handler and named tool groups that an AGENT grants by name) with tools=, provider configuration, and named memory implementations. To pass a provider key without an environment variable, add it to the run's config, as in llm_config={"provider": "anthropic", "model": "claude-sonnet-4-5", "api_key": key}; the key is never recorded or echoed, so pass it again to resume_flow(..., api_key=key) or result.backward(..., api_key=key). A base_url beside the key, such as an Azure OpenAI resource's https://<resource>.openai.azure.com/openai/v1/ with "provider": "openai", is where that key is sent; flow files cannot set it. Without one, the provider's default or environment endpoint applies. Passing learnable=True retains accepted execution for a later explicit result.backward(feedback) call, with or without memory. Each call is a new attempt, so feedback can arrive several times, days later. Forward execution returns before any learning or commit; memory recall is independent. The returned BackwardOutcome and result.backward_outcome keep feedback and learning separate from the forward output and failure. See the Python API for feedback shapes, memory, and silent terminal recovery.

Pass on_stream= to receive an AGENT's reply text as it is generated. Pass on_event= to receive node transitions plus, while an AGENT runs, per-call ModelCallFinished token usage and tool call observers. Both are live callbacks only; see Python API for payloads.

A host can steer or interrupt a running tool_calling AGENT that declares steerable: true. Pass steering=inbox, any object with drain(node_id) -> list[str] and interrupted(node_id) -> bool. Queued steers reach the model as user messages at the top of the next loop iteration. An interrupt ends the loop at the next safe point, including mid-stream, and the node succeeds with its text so far. See Steering.

The built-in EpisodicMemory keeps bounded, model-free execution history for later runs. A flow declares a named memory, long_term_memory: {notes: episodic}; its host builds the declared backends with build_memories (in RAM unless given storage) and commits retained episodes through explicit backward:

from yian import build_memories

with build_memories(flow) as memory:
    result = run_flow(flow, inputs, memory=memory, learnable=True)
    result.backward()

ProfileMemory keeps one markdown document, such as a person's profile, in a versioned file. Every AGENT under the declaring flow sees the whole document; backward rewrites it with one model call and a compare-and-set write. Declare long_term_memory: {about: profile} and supply the backend under its key:

from yian import build_memories
from yian.memory.profile import ProfileMemory
from yian.memory.storage import FileMarkdownStore

profile = ProfileMemory(FileMarkdownStore("people/ada.md"))
with build_memories(flow, supplied={"about": profile}) as memory:
    result = run_flow(flow, inputs, memory=memory, learnable=True)
    result.backward("Ada prefers short replies.")

SessionMemory supplies a structured session transcript through the same memory context as notes from other memories. It keeps conversation history across runs in the same process. Declare long_term_memory: {chat: session} on the AGENT and reuse one registry:

from yian import build_memories

with build_memories(flow) as memory:
    first = run_flow(flow, first_inputs, memory=memory)
    second = run_flow(flow, next_inputs, memory=memory)
    memory["chat"].reset()  # Starts fresh; fails while any turn is active or queued.

History advances automatically, without learnable=True or backward. Every call site of the declaring AGENT shares its one conversation, and calls queue in admission order. Two AGENTs cannot share a session key, so each keeps a separate conversation. Explicit backward learning reuses API self-feedback as committed notes for future runs, without another model call. API history uses a soft 32,000-character context budget and preserves the latest four whole turns; older context can be summarized without deleting raw history. Configure these defaults on SessionMemory(history_budget_chars=32_000, recent_turns=4). Run logs do not reconstruct history. The episodic, reflective, and session backends optionally retain their state across restarts in a SQLite file. build_memories places one memory with storage={key: path}, or every memory under root= (the flow id: must be usable as one directory name):

with build_memories(flow, storage={"chat": "./session.sqlite"}) as memory:
    result = run_flow(flow, inputs, memory=memory)

An AGENT can also use Claude Code and Codex skills. skills: [release-notes] (or skills: all) lists each granted skill's name and description in the system message, and the model reads a skill's SKILL.md or bundled files through the built-in load_skill tool when it needs them. yian run supplies the skills in ~/.claude/skills, ~/.agents/skills, and the project's .claude/skills and .agents/skills; a library host passes skills=load_skills([...]) from yian.compose ({} when a granting flow should get none). See Skills.

Each local SQLite file has one owning backend until close() or context exit. Idle run handles do not block closing; active work or queued turns do. Omit storage to keep memory process-local. See durable memory for ownership and recovery.

yian run builds every declared built-in memory (episodic, reflective, session, profile). They stay in RAM unless a CLI option places them:

yian run flow.yaml --memory-root ./mem
yian run flow.yaml --resume ./run.jsonl --memory-root ./mem

--memory-root DIR keeps every memory under DIR/<flow id>/ (the flow id: must be usable as one directory name), and repeatable --memory-storage KEY=PATH places one declared memory. Use the same storage on resume; a run log is not a memory backup. The CLI does not run backward learning. A flow that declares a custom memory type runs from Python with build_memories; yian run exits 1 with a setup error for it. See CLI memory for lifetime and examples.

Documentation

  • Agent — what “agent,” node, flow, child flow, memory, and run mean in this framework.
  • Architecture — how YAML becomes a compiled flow and a RunResult.
  • Flow syntax — the complete authoring reference.
  • Examples — annotated flows from examples/.
  • Compose — parsing, lowering, validation, and source origins.
  • The engine — scheduling, records, recovery, and learning.
  • Runtime nodes — the Node / NodeResult contract.
  • Engine design — contributor invariants and package ownership.

Develop and test

pip install -e ".[all,dev]"
PYTHONPATH=src python -m pytest

See Contributing for the issue/branch/PR workflow and Installation for local environment setup.

License

Apache 2.0 — see LICENSE.

Metadata

Release files for yian 0.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yian 0.0.3
File Size Uploaded Provenance
yian-0.0.3.tar.gz 683.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for yian 0.0.3
File Interpreter ABI Platform
yian-0.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 1.4 MB

Release files / yian-0.0.3.tar.gz

Download URL yian-0.0.3.tar.gz
Size 683.2 kB
Tags Source
SHA-256 checksum
How to use checksums
9cf0539f03942fa116d02dc9f0a152c032321c1a15742e724fcca31332422a52
BLAKE2b-256 checksum
How to use checksums
f25a209dee6bcda60ba878e12989bd1ac646e28e03bbef03c5570dc75700049c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

Release files / yian-0.0.3-py3-none-any.whl

Download URL yian-0.0.3-py3-none-any.whl
Size 753.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c8f9f46f19b5532437b4f302d145c71fd24b7e08cfdaf752079b3714edf70734
BLAKE2b-256 checksum
How to use checksums
b2070d6a99b878a4c1a4347b5f16eafda535444fe7e03c38e05ed7982bebbb08
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

Security for yian 0.0.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for yian-0.0.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.3 This release

2 release files Full provenance

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