Sources
A Source is the polymorphic type used by every content-bearing field in a Workflow: Node instructions, workflow input.rules[] and input.context[], and issue/PR templates. A Source can be inline text, a local file path, or an HTTP(S) URL.
A Source takes one of four shapes:
# 1. Inline text (ergonomic default)instruction: "Investigate the alert and classify each issue."
# 2. Relative or absolute file pathinstruction: "./prompts/investigate.md"instruction: "/opt/prompts/investigate.md"
# 3. HTTP(S) URLinstruction: "https://raw.githubusercontent.com/acme/playbook/main/investigate.md"
# 4. Tagged object form (escape hatch for ambiguous strings)instruction: { inline: "./literal/slash/is-not-a-file" }instruction: { file: "./prompts/investigate.md" }instruction: { url: "https://x.test/playbook.md", type: "fetch" }The string form classifies by prefix:
| Prefix | Kind | Example |
|---|---|---|
./, ../, / | file | ./rules.md |
http://, https:// | url | https://x/y.md |
| anything else | inline | Just be helpful. |
Resolution Semantics
Section titled “Resolution Semantics”A conforming executor MUST resolve every Source in a workflow before any node executes. Resolution happens once per run. Results are available to the executor and recorded in the Execution Trace for auditability.
- Inline — identity; the string is used as-is.
- File — read via UTF-8
readFile. Relative paths resolve against the workflow file’s directory or the CLI’s cwd. - URL —
fetch()with 10s timeout,http/httpsonly. Hosts that resolve to private, loopback, or link-local addresses (including the cloud metadata endpoint) are rejected, and every redirect hop is re-validated. Authorization header picked from.sweny.ymlfetch.auth(per-host env-var-name mapping);SWENY_FETCH_TOKENsupplies the value but is only sent to hosts you configure infetch.auth(no blanket fallback to arbitrary hosts).
In-run cache
Section titled “In-run cache”Files and URLs are cached by canonical key (absolute path / full URL) for the lifetime of a single workflow run. The same URL referenced from multiple fields is fetched once.
--offline flag
Section titled “--offline flag”When the CLI is invoked with --offline:
- File and inline Sources resolve normally.
- URL Sources MUST fail the run at load time with
SOURCE_OFFLINE_REQUIRES_FETCH.
ResolvedSource
Section titled “ResolvedSource”Each resolved Source produces a record:
| Field | Type | Description |
|---|---|---|
content | string | The resolved body. |
kind | "inline" | "file" | "url" | Classification. |
origin | Source | Original YAML value. |
resolver | "inline" | "file" | "fetch" | Name of the resolver that produced content. |
hash | string | sha256 hex, first 16 chars. |
fetchedAt | string? | ISO 8601; present when kind === "url". |
sourcePath | string? | Absolute path; present when kind === "file". |
Traces record these under trace.sources, keyed by field path (e.g. nodes.investigate.instruction).
Error Codes
Section titled “Error Codes”| Code | When |
|---|---|
SOURCE_FILE_NOT_FOUND | File path does not exist. |
SOURCE_FILE_READ_FAILED | Any other filesystem error. |
SOURCE_URL_UNREACHABLE | Network error, DNS failure, or timeout. |
SOURCE_URL_HTTP_ERROR | Non-2xx response. |
SOURCE_URL_AUTH_REQUIRED | HTTP 401 or 403. |
SOURCE_OFFLINE_REQUIRES_FETCH | URL Source encountered with --offline. |
SOURCE_INVALID_TYPE | Tagged URL with an unknown type (v1 accepts only "fetch"). |
SOURCE_INVALID_SHAPE | Tagged object with zero or multiple tag keys, or extra keys. |
Fields That Use Source
Section titled “Fields That Use Source”node.instruction— Nodesworkflow.rules[]— Workflowworkflow.context[]— Workflownode.rules[]/node.context[]— Nodes (per-node knowledge)workflow.input.rules[]— Workflow — Runtime Inputworkflow.input.context[]— Workflow — Runtime InputissueTemplate,prTemplate(executor-specific)
Fields That Stay Plain Strings
Section titled “Fields That Stay Plain Strings”Identifiers, display names, and routing logic (workflow.id, node.name, edge.when, skill.id, node.skills[]) remain plain strings. Routing conditions are workflow-local and tightly coupled to the DAG; they do not benefit from externalization.