diff --git a/graphs/README.md b/graphs/README.md index 450bb36..c46be46 100644 --- a/graphs/README.md +++ b/graphs/README.md @@ -58,6 +58,7 @@ uses network access, provider credentials, or paid services. - [Music Visualizer](media/audio/music-visualizer.notes.md) · - [Music Beat Grid](media/audio/music-beat-grid.notes.md) · - [Cut Timeline Renderer](media/video/cut-timeline-renderer.notes.md) · +- [Media Probe Normalize](media/video/media-probe-normalize.notes.md) · ## AI @@ -103,9 +104,15 @@ uses network access, provider credentials, or paid services. [Browse pipe examples](pipes/README.md). +- [Approval Gate](pipes/jobs/approval-gate.notes.md) · +- [Audit Log Write](pipes/http/audit-log-write.notes.md) · - [Contact CSV Deduplicator](pipes/contacts/contact-csv-deduplicator.notes.md) · +- [Fallback Match](pipes/transforms/fallback-match.notes.md) · +- [Job Run](pipes/jobs/job-run.notes.md) · +- [LLM Call](pipes/http/llm-call.notes.md) · - [Open Tickets Pipe](pipes/transforms/open-tickets-pipe.notes.md) · - [Plain HTTP Response](pipes/http/plain-http-response.notes.md) · +- [Render Job](pipes/jobs/render-job.notes.md) · - [RSS News Digest](pipes/feeds/rss-news-digest.notes.md) · - [URL Extract Pipe](pipes/transforms/url-extract-pipe.notes.md) · diff --git a/graphs/media/README.md b/graphs/media/README.md index 7cb17d3..b4b0948 100644 --- a/graphs/media/README.md +++ b/graphs/media/README.md @@ -14,3 +14,4 @@ Examples that inspect, transform, or present uploaded audio and video. [Browse video media examples](video/README.md). - [Cut Timeline Renderer](video/cut-timeline-renderer.notes.md) · +- [Media Probe Normalize](video/media-probe-normalize.notes.md) · diff --git a/graphs/media/video/README.md b/graphs/media/video/README.md index bc8a4ed..dc2102e 100644 --- a/graphs/media/video/README.md +++ b/graphs/media/video/README.md @@ -1,3 +1,4 @@ # Video Media Examples - [Cut Timeline Renderer](cut-timeline-renderer.notes.md) · +- [Media Probe Normalize](media-probe-normalize.notes.md) · diff --git a/graphs/media/video/media-probe-normalize.notes.md b/graphs/media/video/media-probe-normalize.notes.md new file mode 100644 index 0000000..3246820 --- /dev/null +++ b/graphs/media/video/media-probe-normalize.notes.md @@ -0,0 +1,62 @@ +# Media Probe Normalize + +![Media Probe Normalize example thumbnail](media-probe-normalize.thumbnail.jpg) + + + +A reusable probe for one audio or video artifact. It reads the file's technical facts +with the Media Probe node and projects them into a stable, small shape with a mapping, +so downstream nodes depend on fixed field names rather than the raw probe layout. Use it +for clip durations, QA measurements, or upload verification. Import it independently, or +publish it as a composite. + +The graph needs a worker with the `media-worker` capability. It makes no network +requests, needs no credentials, and has no side effects. Media Probe runs with a +15-second timeout. + +## Data flow + +1. **Probe media** (`n_media_probe`) inspects the `artifact` input and emits the raw probe + information. +2. **Normalize facts** (`n_map_fields`) copies fields from the raw information into the + shape given by `mapping`. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `artifact` | `artifact` | Required audio or video file, for example an uploaded asset | +| `mapping` | `json` | Optional map from output field names to probe field names | + +| Output | Type | Meaning | +| --- | --- | --- | +| `facts` | `json` | The projected facts | +| `raw` | `json` | The unmodified probe information | + +The default mapping carries `duration_seconds`, `width`, `height`, `fps`, and `has_audio` +across under the same names. That is a guess at the probe's key layout. Run the graph +once, compare `raw` with `facts`, and adjust `mapping` if a field comes back empty. + +## Authentication and security + +There is nothing to wire. The graph holds no credentials and calls no service. Probe +output can include file metadata such as titles and encoder tags, so treat `raw` as +untrusted input when it is displayed or passed to another service. + +## Recommended panels + +Use a JSON Inspector for `facts` and `raw`, and Activity or Logs to see worker errors. + +## Using it as a composite + +Publish the graph and call it from a parent that produces or receives an `artifact`, such +as a render step or an upload. Connect `facts` to checks like a duration limit, and keep +`raw` for diagnostics. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. It has not been executed on a media worker, so the default +mapping is unconfirmed, and whether the account plan includes the `media-worker` capability has not +been verified. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/media/video/media-probe-normalize.subfork.json b/graphs/media/video/media-probe-normalize.subfork.json new file mode 100644 index 0000000..4f4158c --- /dev/null +++ b/graphs/media/video/media-probe-normalize.subfork.json @@ -0,0 +1,144 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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", + "definition": { + "version": "0.1.0", + "name": "Media Probe Normalize", + "description": "Media probe and normalize. Probes one artifact and returns the raw probe info and the facts projected through the mapping input. The default mapping is a guess at the probe key layout and must be confirmed with one run on a media worker. Needs the media-worker capability. No network, no credentials.", + "nodes": [ + { + "node_instance_id": "probe", + "node_id": "n_media_probe", + "node_version": "1.0.0", + "title": "Probe media", + "params": { + "timeout_seconds": 15 + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "norm", + "node_id": "n_map_fields", + "node_version": "1.0.0", + "title": "Normalize facts", + "params": { + "mapping": { + "duration_seconds": "duration_seconds", + "width": "width", + "height": "height", + "fps": "fps", + "has_audio": "has_audio" + } + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "probe", + "source_output": "info", + "target_node_id": "norm", + "target_input": "value" + } + ], + "graph_inputs": { + "artifact": { + "type": "artifact", + "required": true, + "default_node": "probe", + "default_input": "artifact" + }, + "mapping": { + "type": "json", + "required": false, + "default_node": "norm", + "default_param": "mapping" + } + }, + "graph_outputs": { + "facts": { + "node_instance_id": "norm", + "output_name": "value" + }, + "raw": { + "node_instance_id": "probe", + "output_name": "info" + } + }, + "metadata": { + "template": { + "category": "media", + "status": "media-worker-probe", + "summary": "Probes one audio or video artifact and projects the facts into a stable shape.", + "composite_interface": { + "inputs": { + "artifact": { + "type": "artifact", + "required": true, + "default_node": "probe", + "default_input": "artifact" + }, + "mapping": { + "type": "json", + "required": false, + "default_node": "norm", + "default_param": "mapping" + } + }, + "outputs": { + "facts": { + "type": "json", + "node_instance_id": "norm", + "output_name": "value" + }, + "raw": { + "type": "json", + "node_instance_id": "probe", + "output_name": "info" + } + } + }, + "requires": { + "nodes": [ + "n_map_fields", + "n_media_probe" + ], + "panels": [ + "json" + ], + "capabilities": [ + "media-worker" + ], + "secrets": [] + } + }, + "canvas": { + "positions": { + "probe": { + "x": 80, + "y": 80 + }, + "norm": { + "x": 380, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "media", + "video" + ] +} diff --git a/graphs/media/video/media-probe-normalize.thumbnail.jpg b/graphs/media/video/media-probe-normalize.thumbnail.jpg new file mode 100644 index 0000000..dfeeb1d Binary files /dev/null and b/graphs/media/video/media-probe-normalize.thumbnail.jpg differ diff --git a/graphs/pipes/README.md b/graphs/pipes/README.md index 49eab19..8324087 100644 --- a/graphs/pipes/README.md +++ b/graphs/pipes/README.md @@ -12,9 +12,20 @@ These examples demonstrate small reusable data-ingestion and transformation pipe ## HTTP +- [Audit Log Write](http/audit-log-write.notes.md) · +- [LLM Call](http/llm-call.notes.md) · - [Plain HTTP Response](http/plain-http-response.notes.md) · +## Jobs + +[Browse job examples](jobs/README.md). + +- [Approval Gate](jobs/approval-gate.notes.md) · +- [Job Run](jobs/job-run.notes.md) · +- [Render Job](jobs/render-job.notes.md) · + ## Transforms +- [Fallback Match](transforms/fallback-match.notes.md) · - [Open Tickets Pipe](transforms/open-tickets-pipe.notes.md) · - [URL Extract Pipe](transforms/url-extract-pipe.notes.md) · diff --git a/graphs/pipes/http/audit-log-write.notes.md b/graphs/pipes/http/audit-log-write.notes.md new file mode 100644 index 0000000..5352c00 --- /dev/null +++ b/graphs/pipes/http/audit-log-write.notes.md @@ -0,0 +1,100 @@ +# Audit Log Write + +![Audit Log Write example thumbnail](audit-log-write.thumbnail.jpg) + + + +A reusable audit-record append built from generic nodes. It builds one record from +an actor, an action, a subject ID, and a payload, POSTs it to a sink URL the caller +supplies, and reads the new record's `id` from the response. Use it to leave a +durable trail of approvals, write-backs, exports, or filings from any parent graph. +Import it independently, or publish it as a composite. + +**This graph performs an externally visible write.** Every successful run appends a +record at the sink. Re-running after an ambiguous timeout can append a duplicate, +and the graph cannot delete a record it wrote. The graph references no secrets, +environment-specific graph IDs, or generated media. + +## Data flow + +1. **Audit record** (`n_json_template`) builds `actor`, `action`, `subject_id`, + `payload`, and an optional `occurred_at`. +2. **Append record** (`n_fetch_url`) POSTs the record to `sink_url` with the + `headers` input. The request has a 30-second timeout. The response-size limit + is the node default. +3. **Record id** (`n_json_path`) reads `id` from the JSON response. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `sink_url` | `url` | Required endpoint that accepts the record. Receives the `headers` value | +| `headers` | `json` | Required request headers, built by the parent graph | +| `actor` | `str` | Required identity that performed the action | +| `action` | `str` | Required short action name | +| `subject_id` | `str` | Required identifier of the thing acted on | +| `payload` | `json` | Required structured details of the action | +| `occurred_at` | `str` | Optional timestamp the caller supplies | + +| Output | Type | Meaning | +| --- | --- | --- | +| `record_id` | `json` | The `id` field of the sink response | +| `response` | `json` | The full JSON response from the sink | +| `status` | `int` | HTTP status code | + +Subfork has no clock node, so the graph cannot stamp the time itself. Pass +`occurred_at` from the parent or let the sink stamp the record. The record template +marks that key as optional (`occurred_at?`); omission of the field when the input is +absent is assumed and has not been confirmed in a live run. + +## Authentication + +The graph never holds a credential. The parent builds the headers from its own +secrets and passes them in: + +1. In the parent, add a JSON Template node with the template + `{"Authorization": "Bearer {{ secrets.AUDIT_SINK_TOKEN }}", "Content-Type": "application/json"}`. +2. Connect its `value` output to this graph's `headers` input. +3. Add the secret `AUDIT_SINK_TOKEN` in the parent graph's **Graph Settings → + Execution Profile**. Never paste a token into a graph, a fixture, or these notes. + +Use whatever header names and secret name your sink requires. Whether node outputs +and execution logs redact header values has not been verified, so do the first run +with a throwaway token and inspect the logs before using a real one. + +## Security guidance + +- **Use a literal URL in the parent graph.** `sink_url` receives the headers, + including the token. Do not feed it from request data, model output, or any other + untrusted value. +- **Use a low-privilege, append-only token.** The token should allow creating + records and nothing else. Do not reuse it for other services. +- **Do not put secrets in `payload`.** Records are stored by the sink and are + usually readable by more people than the original data. + +## Retry and duplication + +The graph does not retry and does not send an idempotency key. If the sink supports +one, add it to the payload or the headers from the parent. After a timeout, look +for the record at the sink before running again. + +## Using it as a composite + +Publish the graph, pin the version, and call it from a parent after the step you +want to record. Connect the step's result into `payload` and `subject_id`, and use +`record_id` to link the record from later steps. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. + +It was imported and executed once on subfork.com on 2026-11-05 by anthonyshafer@gmail.com, and the +run completed. The run POSTed fixture values to the public test endpoint +`https://jsonplaceholder.typicode.com/posts`, not a real audit sink, with no credentials. The +endpoint answered 201 with an `id` of 101, which the graph returned as `record_id`, and a JSON +object passed as `payload` was sent as an object. Its nodes, edges, and graph inputs and outputs +match this file; the test run only filled in `sink_url`, `headers`, and the record fields. Whether +the endpoint stored the record was not checked. Behavior against a real sink, idempotency, and +header redaction in logs are unverified. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/pipes/http/audit-log-write.subfork.json b/graphs/pipes/http/audit-log-write.subfork.json new file mode 100644 index 0000000..2e23eb7 --- /dev/null +++ b/graphs/pipes/http/audit-log-write.subfork.json @@ -0,0 +1,256 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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yDzGciGWriZX2awNttJQW+KVkMlOy4NZI2ZrHhwcS0PEbn7XOaJHMLwDgHkFFo62phmhmjqZo5oQGxSMlcHRgdgaQctA9GOxTeC0rAXPh/QUNrq7rSaQprnXu062tjpRbaiCAztuHVOkbTOdvGIiC5meY57QCvMusdDo7SmrqpunqKKpmttjqquy1THup6OrkklLmmMuyBgBwjceW/B7MLVNr1pdrTb7rSQ1Urm3FjGPlfNIZIi2Vsu+M7vNcXMGT6QvHkq55eu3zyv68h0u6QnrDnILsnzjn0lN6PpFpS/iNZrTZuI8tK2CS3WiRtHUSQ0Y3ugZLBFJIIg888F7tocfUMrz9EG7w6wjm0tEam5wNqJaQSsaZNrY3kvDScdYGZcAMncBtyQFHpZpKh++WR8r8AbpHFxwBgDJ9QAC5UtVPQ1MVRTTSU9RE4PjmieWPY4dhBHMH6QqX53W+mxuKNSy58PdDV8FRc6iForqfrL4d1a94ex7iH5IdCN4DfUd4K9u/wBmsTxqSzxaet9CLfpeju0dwiY/wkVBjpXPeXF2NjhK7LMY9PatT3m/XPUdWKq7XGrudSG7BNWTuleG+oFxOB9CxzWVDnPcaiUuewRvJkdlzBjDTz5jkOR5ch6lbeRZvt/DuxVWpr3Zbnp+Gwaat1XRQ2/UDA+OSrbJURR+dM5xZN1sTpH5A8zGRgArstumor1bKe06g0tDo62T6zpqORtPHLT9bG2Coww73EuOcN6wfG3+sLQM1dU1FNFTy1M8tPDnqoZJXOZHnt2tJw39i+1NyrK1gbUVlRUNAaA2aZzwAAQ0YJPZk49WSp3o7Fm/HaI09JUWmqn006SrMtc00VFZ56RskccAcHmlmlD5zE8jIYQXjIyS0rWHFmwMsOoKIxUtHRxVlBFVNjooJqdpBLm7nQS+dC47c7MkdhHJyict0rZ6qOplraqWpiAEc753ukYB2bXE5GPRgrqqamasnfPUTS1E7zl0szy97j9LiSSomYmOhEOtERUWEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARF69v0+6pgZUVM4pYJBlgDd8jxnGQ3IwOXaSPoUxE1coRM2eQikXwcoPnCo+6t/GnwcoPnCp+6t/GtPjqV3oR1FIvg5QfOFT91b+NPg5QfOFT91b+NPjqN6EdRSL4OUHzhU/dW/jT4OUHzhU/dW/jT46jehHUUi+DlB84VP3Vv40+DlB84VP3Vv40+Oo3oR1FIvg5QfOFT91b+NPg5QfOFT91b+NPjqN6EdRSL4OUHzhU/dW/jT4OUHzhU/dW/jT46jehHUUi+DlB84VP3Vv418OmqJwwy4yh3oMlNhv7cOJ/yUfHUb0I8iya+3zW2o6qYNyWhzXMOWvaewg+pYypMW5SsIiKEiLOtlolue94eyCCMgPmk7AT2AAcyeXYP8l6nwboPnCoz9FKPxq8UVTzhWaohHUUi+DlB84VP3Vv40+DlB84VP3Vv41b46kb0I6ikXwcoPnCp+6t/GnwcoPnCp+6t/Gnx1G9COopF8HKD5wqfurfxp8HKD5wqfurfxp8dRvQjqKRfByg+cKn7q38afByg+cKn7q38afHUb0I6ikXwcoPnCp+6t/GnwcoPnCp+6t/Gnx1G9COopF8HKD5wqfurfxp8HKD5wqfurfxp8dRvQjqKRfByg+cKj7q38a8252WS2sbKJGVFM520SsBGHYzgtPMH/I+gqs0VRF5TFUS89ERUWERd9FRTXCpbBA0OkcCeZAAAGSST2ABOqHQikLdNUbWgSXGRz/SYabLf2Fzgf8AJffg5QfOFT91b+NafHUrvQjqKRfByg+cKn7q38afByg+cKn7q38an46jehHUUi+DlB84VP3Vv40+DlB84VP3Vv40+Oo3oR1FIvg5QfOFT91b+NPg5QfOFT91b+NPjqN6EdRSL4OUHzhU/dW/jT4OUHzhU/dW/jT46jehHUUi+DlB84VP3Vv4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", + "definition": { + "version": "0.1.0", + "name": "Audit Log Write", + "description": "Audit record append over HTTP. Builds one record from actor, action, subject_id, payload, and an optional occurred_at, POSTs it to sink_url, and returns the record id, the sink response, and the HTTP status. This is an externally visible write, and a retry can append a duplicate record. There is no clock node, so the caller passes occurred_at or the sink stamps it. Credentials arrive only through the headers input. This graph references no secrets.", + "nodes": [ + { + "node_instance_id": "rec", + "node_id": "n_json_template", + "node_version": "1.0.0", + "title": "Audit record", + "params": { + "template": { + "actor": "{{ inputs.actor }}", + "action": "{{ inputs.action }}", + "subject_id": "{{ inputs.subject_id }}", + "payload": "{{ inputs.payload }}", + "occurred_at?": "{{ inputs.occurred_at }}" + } + }, + "custom_inputs": { + "actor": "str", + "action": "str", + "subject_id": "str", + "payload": "json", + "occurred_at": "str" + }, + "exposed_inputs": [ + "actor", + "action", + "subject_id", + "payload", + "occurred_at" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "write", + "node_id": "n_fetch_url", + "node_version": "1.0.0", + "title": "Append record", + "params": { + "method": "POST", + "timeout_seconds": 30 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "body" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "id", + "node_id": "n_json_path", + "node_version": "1.0.0", + "title": "Record id", + "params": { + "path": "id" + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "rec", + "source_output": "value", + "target_node_id": "write", + "target_input": "body" + }, + { + "source_node_id": "write", + "source_output": "json", + "target_node_id": "id", + "target_input": "value" + } + ], + "graph_inputs": { + "sink_url": { + "type": "url", + "required": true, + "default_node": "write", + "default_param": "url" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "write", + "default_param": "headers" + }, + "actor": { + "type": "str", + "required": true, + "default_node": "rec", + "default_input": "actor" + }, + "action": { + "type": "str", + "required": true, + "default_node": "rec", + "default_input": "action" + }, + "subject_id": { + "type": "str", + "required": true, + "default_node": "rec", + "default_input": "subject_id" + }, + "payload": { + "type": "json", + "required": true, + "default_node": "rec", + "default_input": "payload" + }, + "occurred_at": { + "type": "str", + "required": false, + "default_node": "rec", + "default_input": "occurred_at" + } + }, + "graph_outputs": { + "record_id": { + "node_instance_id": "id", + "output_name": "value" + }, + "response": { + "node_instance_id": "write", + "output_name": "json" + }, + "status": { + "node_instance_id": "write", + "output_name": "status" + } + }, + "metadata": { + "template": { + "category": "pipes", + "status": "network-probe", + "summary": "Externally visible write: POSTs one audit record to a caller-supplied sink and reads back its id.", + "composite_interface": { + "inputs": { + "sink_url": { + "type": "url", + "required": true, + "default_node": "write", + "default_param": "url" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "write", + "default_param": "headers" + }, + "actor": { + "type": "str", + "required": true, + "default_node": "rec", + "default_input": "actor" + }, + "action": { + "type": "str", + "required": true, + "default_node": "rec", + "default_input": "action" + }, + "subject_id": { + "type": "str", + "required": true, + "default_node": "rec", + "default_input": "subject_id" + }, + "payload": { + "type": "json", + "required": true, + "default_node": "rec", + "default_input": "payload" + }, + "occurred_at": { + "type": "str", + "required": false, + "default_node": "rec", + "default_input": "occurred_at" + } + }, + "outputs": { + "record_id": { + "type": "json", + "node_instance_id": "id", + "output_name": "value" + }, + "response": { + "type": "json", + "node_instance_id": "write", + "output_name": "json" + }, + "status": { + "type": "int", + "node_instance_id": "write", + "output_name": "status" + } + } + }, + "requires": { + "nodes": [ + "n_fetch_url", + "n_json_path", + "n_json_template" + ], + "panels": [ + "json" + ], + "capabilities": [ + "public-http", + "external-write" + ], + "secrets": [] + } + }, + "canvas": { + "positions": { + "rec": { + "x": 80, + "y": 80 + }, + "write": { + "x": 380, + "y": 80 + }, + "id": { + "x": 680, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "pipes", + "http", + "operations" + ] +} diff --git a/graphs/pipes/http/audit-log-write.thumbnail.jpg b/graphs/pipes/http/audit-log-write.thumbnail.jpg new file mode 100644 index 0000000..e08723e Binary files /dev/null and b/graphs/pipes/http/audit-log-write.thumbnail.jpg differ diff --git a/graphs/pipes/http/llm-call.notes.md b/graphs/pipes/http/llm-call.notes.md new file mode 100644 index 0000000..9083236 --- /dev/null +++ b/graphs/pipes/http/llm-call.notes.md @@ -0,0 +1,101 @@ +# LLM Call + +![LLM Call example thumbnail](llm-call.thumbnail.jpg) + + + +A reusable synchronous chat-completion call built from generic nodes. It builds an +OpenAI-style chat request body from a prompt, a system message, and a model name, +POSTs it to a URL the caller supplies, and extracts the reply text from the +response. It is provider-neutral: any endpoint that accepts that request shape and +returns the reply at a known path works. Import it independently, or publish it as +a composite and call it from a parent graph as a single node. + +The graph references no secrets, environment-specific graph IDs, or generated +media. + +## Data flow + +1. **Chat request body** (`n_json_template`) builds `model` plus a `messages` array + with one `system` and one `user` message. +2. **Model call** (`n_fetch_url`) POSTs the body to `url` with the `headers` input. + The request has a 60-second timeout. The response-size limit is the node default + and is not overridden here. +3. **Reply text** (`n_json_path`) reads `reply_path` from the JSON response. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `url` | `url` | Required chat endpoint. Receives the `headers` value, so see the security notes | +| `headers` | `json` | Required request headers, built by the parent graph (see Authentication) | +| `prompt` | `str` | Required user message | +| `system` | `str` | Required system message | +| `model` | `str` | Required model name the endpoint understands | +| `reply_path` | `str` | Optional path to the reply text; defaults to `choices.0.message.content` | + +| Output | Type | Meaning | +| --- | --- | --- | +| `reply` | `json` | The value found at `reply_path` | +| `response` | `json` | The full JSON response from the endpoint | +| `status` | `int` | HTTP status code | + +Change `reply_path` for providers that return the text elsewhere. The `response` +output is there for inspection when the path does not match. + +## Authentication + +The graph never holds a credential. The parent graph owns the secret and passes +request headers in through the `headers` input: + +1. In the parent, add a JSON Template node with the template + `{"Authorization": "Bearer {{ secrets.LLM_API_KEY }}", "Content-Type": "application/json"}`. +2. Connect its `value` output to this graph's `headers` input. +3. Add the secret `LLM_API_KEY` in the parent graph's **Graph Settings → Execution + Profile**. Never paste a key into a graph, a fixture, or these notes. + +Use whatever header names and secret name your endpoint requires. Whether node +outputs and execution logs redact header values has not been verified, so do the +first run with a throwaway key and inspect the logs before using a real one. + +## Security guidance + +- **Use a literal URL in the parent graph.** The `url` input receives the headers, + including the bearer token. Do not feed it from request data, model output, or + any other untrusted value, or the token is sent to whatever host that value + names. Pin it to the provider origin you intend. +- **Use a low-privilege key.** Prefer a key scoped to this one use, with a spending + limit where the provider offers one. +- **The prompt leaves your instance.** Every run sends the prompt and system + message to the endpoint. Do not pass data you are not allowed to share with that + provider. + +## Cost and limits + +Each run makes one POST that can be billed by the provider. The graph does not +retry. If a run ends with an unknown outcome, check the provider before running it +again, because a second run can be billed again. Provider rate limits, context +limits, and terms apply. + +## Using it as a composite + +Publish the graph and call it from a parent that supplies `url` and `headers` as +literals or from its own secrets, and passes `prompt`, `system`, and `model` from +upstream nodes. Pin the published version when the parent depends on its behavior, +and record which version the parent was tested with. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. + +It was imported and executed once on subfork.com on 2026-11-05 by anthonyshafer@gmail.com, and the +run completed. The run called the public echo endpoint `https://httpbin.org/anything`, not a +model provider, and sent no credentials. Its nodes, edges, and graph inputs and outputs match this +file. The test run used fixture values for the inputs and set `reply_path` to +`json.messages.1.content`, which reads the prompt back from the echoed body, instead of the default +`choices.0.message.content`. The run confirmed that placeholders nested inside the array and object +of the request template resolve as intended: the system and user messages arrived with the +fixture text. It did not exercise the default reply path or a real provider response, so provider +behavior, billing, and rate limits are unverified. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/pipes/http/llm-call.subfork.json b/graphs/pipes/http/llm-call.subfork.json new file mode 100644 index 0000000..6d35bff --- /dev/null +++ b/graphs/pipes/http/llm-call.subfork.json @@ -0,0 +1,245 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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ymhNW10Ty6GeEVHC5fmt1uRkjMhcPWzCjNbqW7VNLNTU1vhtFPM5j5I7VSPpw8ta9ozgk8xI4EdR5exeQPGQphTDw0UwziAcThjPX6PVzwPV6kGyqmyaei1TRiCw19HbJbBLVudNK2Vk3+ob+9ETG1u+12cu5+lzw3GFA9X2mks93ZHQccUc9LT1cTKlwdIxssTX7rnAAOwSRkAZ9iwi65uijiJrTFEHNjjJk3WB3yg0dQB9YHX610vpquQgvhqHkANBcxxwByA6uoIMdF3+BVPZpvdO7k8CqezTe6d3KWkKL+m032rP4goncvnGr+3k/iKlvzVu1lY0xRxnfYx/oulcOprQefX1nqAyoZJI6aR8jzl73Fzj9ZOStOL9Q2UOKIi520REQFyY90Tw9jnMeOpzTgj9q4ogyPGVZ2uo987vTxlWdrqPfO71joreUZHjKs7XUe+d3p4yrO11Hvnd6x0S8jI8ZVna6j3zu9PGVZ2uo987vWOiXkZHjKs7XUe+d3p4yrO11Hvnd6x0S8jI8ZVna6j3zu9PGVZ2uo987vWOiXkZHjKs7XUe+d3p4yrO11Hvnd6x0S8jI8ZVna6j3zu9cZK2plYWSVM0jD1tfK4g/sJXSiXkERFFEREBZAuNWAAKuoAHqEzu9Y6IMjxlWdrqPfO708ZVna6j3zu9Y6K3lGR4yrO11Hvnd6eMqztdR753esdEvIyPGVZ2uo987vTxlWdrqPfO71jol5GR4yrO11Hvnd6eMqztdR753esdEvIyPGVZ2uo987vTxlWdrqPfO71jol5GR4yrO11Hvnd6eMqztdR753esdEvIyPGVZ2uo987vWOiKAiIiiIiDuirKiBm5HUTRsH+6yRzR+4FcvGVZ2uo987vWOit5RkeMqztdR753enjKs7XUe+d3rHRLyMjxlWdrqPfO708ZVna6j3zu9Y6JeRkeMqztdR753enjKs7XUe+d3rHRLyMjxlWdrqPfO708ZVna6j3zu9Y6JeRkeMqztdR753enjKs7XUe+d3rHRLyMjxlWdrqPfO708ZVna6j3zu9Y6JeRykkfM8vke6R563PcSf3lcURRRERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERB/9k=", + "definition": { + "version": "0.1.0", + "name": "LLM Call", + "description": "Synchronous chat-completion call over HTTP. Builds an OpenAI-style chat body from prompt, system, and model, POSTs it to the url input, and returns the extracted reply, the full response, and the HTTP status. Credentials arrive only through the headers input, which the parent graph builds from its own secrets. This graph references no secrets. Each run sends the prompt to the endpoint and can incur provider cost.", + "nodes": [ + { + "node_instance_id": "body", + "node_id": "n_json_template", + "node_version": "1.0.0", + "title": "Chat request body", + "params": { + "template": { + "model": "{{ inputs.model }}", + "messages": [ + { + "role": "system", + "content": "{{ inputs.system }}" + }, + { + "role": "user", + "content": "{{ inputs.prompt }}" + } + ] + } + }, + "custom_inputs": { + "prompt": "str", + "system": "str", + "model": "str" + }, + "exposed_inputs": [ + "prompt", + "system", + "model" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "call", + "node_id": "n_fetch_url", + "node_version": "1.0.0", + "title": "Model call", + "params": { + "method": "POST", + "timeout_seconds": 60 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "body" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "reply", + "node_id": "n_json_path", + "node_version": "1.0.0", + "title": "Reply text", + "params": { + "path": "choices.0.message.content" + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "body", + "source_output": "value", + "target_node_id": "call", + "target_input": "body" + }, + { + "source_node_id": "call", + "source_output": "json", + "target_node_id": "reply", + "target_input": "value" + } + ], + "graph_inputs": { + "url": { + "type": "url", + "required": true, + "default_node": "call", + "default_param": "url" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "call", + "default_param": "headers" + }, + "prompt": { + "type": "str", + "required": true, + "default_node": "body", + "default_input": "prompt" + }, + "system": { + "type": "str", + "required": true, + "default_node": "body", + "default_input": "system" + }, + "model": { + "type": "str", + "required": true, + "default_node": "body", + "default_input": "model" + }, + "reply_path": { + "type": "str", + "required": false, + "default_node": "reply", + "default_param": "path" + } + }, + "graph_outputs": { + "reply": { + "node_instance_id": "reply", + "output_name": "value" + }, + "response": { + "node_instance_id": "call", + "output_name": "json" + }, + "status": { + "node_instance_id": "call", + "output_name": "status" + } + }, + "metadata": { + "template": { + "category": "pipes", + "status": "network-probe", + "summary": "Synchronous chat-completion call: builds a chat body, POSTs it to a caller-supplied URL, extracts the reply.", + "composite_interface": { + "inputs": { + "url": { + "type": "url", + "required": true, + "default_node": "call", + "default_param": "url" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "call", + "default_param": "headers" + }, + "prompt": { + "type": "str", + "required": true, + "default_node": "body", + "default_input": "prompt" + }, + "system": { + "type": "str", + "required": true, + "default_node": "body", + "default_input": "system" + }, + "model": { + "type": "str", + "required": true, + "default_node": "body", + "default_input": "model" + }, + "reply_path": { + "type": "str", + "required": false, + "default_node": "reply", + "default_param": "path" + } + }, + "outputs": { + "reply": { + "type": "json", + "node_instance_id": "reply", + "output_name": "value" + }, + "response": { + "type": "json", + "node_instance_id": "call", + "output_name": "json" + }, + "status": { + "type": "int", + "node_instance_id": "call", + "output_name": "status" + } + } + }, + "requires": { + "nodes": [ + "n_fetch_url", + "n_json_path", + "n_json_template" + ], + "panels": [ + "json" + ], + "capabilities": [ + "public-http" + ], + "secrets": [] + } + }, + "canvas": { + "positions": { + "body": { + "x": 80, + "y": 80 + }, + "call": { + "x": 380, + "y": 80 + }, + "reply": { + "x": 680, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "pipes", + "http", + "ai" + ] +} diff --git a/graphs/pipes/http/llm-call.thumbnail.jpg b/graphs/pipes/http/llm-call.thumbnail.jpg new file mode 100644 index 0000000..a58de7c Binary files /dev/null and b/graphs/pipes/http/llm-call.thumbnail.jpg differ diff --git a/graphs/pipes/jobs/README.md b/graphs/pipes/jobs/README.md new file mode 100644 index 0000000..5d4405a --- /dev/null +++ b/graphs/pipes/jobs/README.md @@ -0,0 +1,7 @@ +# Job Pipe Examples + +Reusable submit-and-poll graphs for services that run work asynchronously over HTTP. Each one creates work at an external service, so read its notes for the side effects, authentication, and security guidance before running it. + +- [Approval Gate](approval-gate.notes.md) · +- [Job Run](job-run.notes.md) · +- [Render Job](render-job.notes.md) · diff --git a/graphs/pipes/jobs/approval-gate.notes.md b/graphs/pipes/jobs/approval-gate.notes.md new file mode 100644 index 0000000..1b0bd4c --- /dev/null +++ b/graphs/pipes/jobs/approval-gate.notes.md @@ -0,0 +1,110 @@ +# Approval Gate + +![Approval Gate example thumbnail](approval-gate.thumbnail.jpg) + + + +A reusable human-approval step built from the same submit-and-poll nodes as +[Job Run](job-run.notes.md). It asks an HTTP service to open an approval request for a +person, then polls until the request is approved, rejected, or expired. The job `kind` +is fixed to `approval`. Import it independently, or publish it as a composite. + +**Submitting the request is an externally visible write.** A successful run creates an +approval request at the service, which may notify the approver. A retry can create a second +request unless the service honors the idempotency key. The graph references no secrets, +environment-specific graph IDs, or generated media. + +## Read this first: the gate does not block by itself + +Subfork has no pause or skip node. This graph can only order work after it by data +flow, for example by wiring `decision` into an input of the node that performs the +effect. The poll node lists `rejected` and `expired` as failure statuses, but whether a +failed poll stops the nodes that depend on it has not been verified. A rejected approval +might still let a downstream node run. + +Do not rely on this graph alone to protect an action. **The service that performs the +effect must confirm the approval itself** before acting: read the job at its +`status_url` and require status `completed`. Treat this graph as the way to request and +wait for an approval, and the effect service as the enforcement point. + +## Data flow + +1. **Approval request** (`n_json_template`) builds the request body with `kind` set to + `approval`, the `idempotency_key`, and `params` holding `subject`, `summary`, + `approver`, and `expires_in_seconds` (900). The optional `payload` is sent as the job + `inputs`. +2. **Jobs endpoint** (`n_url_builder`) appends `jobs` to `base_url`. +3. **Submit job** (`n_http_submit_job`) POSTs the body and reads the job `id` and + `status_url`. +4. **Poll job** (`n_http_poll_job`) calls the `status_url` every 30 seconds for up to 900 + seconds. `completed` ends the poll successfully. `failed`, `cancelled`, `rejected`, + and `expired` are failure statuses. + +The 900-second request expiry and the 900-second poll budget are set to match. The +longest wall time a single run can wait has not been verified, so confirm a 15-minute +approval fits in one run on your instance. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `base_url` | `url` | Required service base URL; the graph posts to `{base_url}/jobs`. Receives the `headers` value | +| `headers` | `json` | Required request headers, built by the parent graph | +| `subject` | `str` | Required short title of what needs approval | +| `summary` | `str` | Required description for the approver | +| `approver` | `str` | Optional approver identifier the service understands; defaults to empty | +| `payload` | `json` | Optional structured details; defaults to an empty object | +| `idempotency_key` | `str` | Required key that makes a repeated request return the same approval | + +| Output | Type | Meaning | +| --- | --- | --- | +| `decision` | `json` | The final status body | +| `status` | `str` | The final status, normalized to lowercase by the poll node | +| `remote_job` | `json` | The resumable job reference | + +The service is expected to follow the submit and poll shape described in +[Job Run](job-run.notes.md), with `rejected` and `expired` as terminal statuses in +addition to the usual ones. Put a content version in the idempotency key, for example +`:approval:`, so changed content gets a new request. + +## Authentication + +The graph never holds a credential. The parent builds the headers from its own secrets +and passes them in: + +1. In the parent, add a JSON Template node with the template + `{"Authorization": "Bearer {{ secrets.JOB_SERVICE_TOKEN }}", "Content-Type": "application/json"}`. +2. Connect its `value` output to this graph's `headers` input. +3. Add the secret `JOB_SERVICE_TOKEN` in the parent graph's **Graph Settings → + Execution Profile**. Never paste a token into a graph, a fixture, or these notes. + +Whether node outputs and execution logs redact header values has not been verified, so +do the first run with a throwaway token and inspect the logs before using a real one. + +## Security guidance + +- **Use a literal `base_url` in the parent graph.** It receives the headers, including + the token. Do not feed it from request data, model output, or any other untrusted + value. +- **Use a token that can request approvals but cannot grant them.** Do not give this + graph the approver's token. If the graph's token could approve its own requests, the + gate would mean nothing. +- **Keep `status_url` on the same host as `base_url`.** The poll node calls whatever + `status_url` the service returns, with the same headers. Whether the node enforces a + same-host rule has not been verified, so only point this graph at a service you + control or trust. + +## Using it as a composite + +Publish the graph, pin the version, and call it from a parent ahead of the step you want +guarded. Connect `decision` to the guarded step's inputs so it runs after the gate, and +make the guarded service check the approval on its own as described above. Connect +`status` to a details or JSON panel so an operator can see the outcome. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. It has not been executed, so it has not been run against a live +job service and no approval request was created. Whether a failed poll halts dependent nodes is +unverified, as described above. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/pipes/jobs/approval-gate.subfork.json b/graphs/pipes/jobs/approval-gate.subfork.json new file mode 100644 index 0000000..f007479 --- /dev/null +++ b/graphs/pipes/jobs/approval-gate.subfork.json @@ -0,0 +1,347 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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vhrardv8Ib3gk3evd1z9OVUoprjQzmRkU8jXuBmhlY8xTgHO2RvLe0nqCgpWjwVt0pfDoZp6TvGiSOCQRvcM+hxa4D9oK2Ha+HlBeNS3+GaG51rIb4LXGy2Nja6Br3Sf9RINhGxu3G0Bo6824CjTtU1RqKeZmlbFE+CTvAI7QQHHBADhu5gZzj1gLETVd2nrqysc6sbU1jnuqJIw9hk3HLgduMgk9OiWE5umiaCTQ1JWilrI6mltEtV4zia0UU7mVkkex3m5L3gjB3ehowRzWtDyKvCLiaYUx8MNOCD3J7zu8jODt6ek+j0lUfAqn2ab7J3uUBRf02m+tZ+8FE7l8o1f18n7xUt+SttZWNMUcZ3sY/zXSuHRrQefXqegGVDJJHTSPkecve4ucfpJyVji+0NKHlERc7UREQF6Y90Tw9jnMeOjmnBH7V5RBceMqz2uo+2d708ZVntdR9s73q3RTeULjxlWe11H2zvenjKs9rqPtne9W6JeRceMqz2uo+2d708ZVntdR9s73q3RLyLjxlWe11H2zvenjKs9rqPtne9W6JeRceMqz2uo+2d708ZVntdR9s73q3RLyLjxlWe11H2zvenjKs9rqPtne9W6JeRceMqz2uo+2d715kramVhZJUzSMPVr5XEH9hKool5BERQkREQFcC41YAAq6gAegTO96t0QXHjKs9rqPtne9PGVZ7XUfbO96t0U3lC48ZVntdR9s73p4yrPa6j7Z3vVuiXkXHjKs9rqPtne9PGVZ7XUfbO96t0S8i48ZVntdR9s73p4yrPa6j7Z3vVuiXkXHjKs9rqPtne9PGVZ7XUfbO96t0S8i48ZVntdR9s73p4yrPa6j7Z3vVuiXkXHjKs9rqPtne9W6IoBEREiIiCtFWVEDNkdRNGwf+Vkjmj/ACBXrxlWe11H2zverdFN5QuPGVZ7XUfbO96eMqz2uo+2d71bol5Fx4yrPa6j7Z3vTxlWe11H2zverdEvIuPGVZ7XUfbO96eMqz2uo+2d71bol5Fx4yrPa6j7Z3vTxlWe11H2zverdEvIuPGVZ7XUfbO96eMqz2uo+2d71bol5Fx4yrPa6j7Z3vTxlWe11H2zverdEvI9SSPmeXyPdI89XPcSf8yvKIoSIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIP/9k=", + "definition": { + "version": "0.1.0", + "name": "Approval Gate", + "description": "Human approval request over HTTP. POSTs an approval job to base_url/jobs (an externally visible write) and polls every 30 seconds for up to 900 seconds until it completes. rejected and expired are listed as failure statuses. Whether a failed poll stops dependent nodes is unverified, so the effect service must confirm the approval itself, by reading the job's status_url and checking for status completed, before acting. Credentials arrive only through the headers input. This graph references no secrets.", + "nodes": [ + { + "node_instance_id": "hdr", + "node_id": "n_coalesce", + "node_version": "1.0.0", + "title": "Auth headers fan-out", + "params": { + "fallback": {} + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "req", + "node_id": "n_json_template", + "node_version": "1.0.0", + "title": "Approval request", + "params": { + "template": { + "kind": "approval", + "idempotency_key": "{{ inputs.idempotency_key }}", + "params": { + "subject": "{{ inputs.subject }}", + "summary": "{{ inputs.summary }}", + "approver": "{{ inputs.approver }}", + "expires_in_seconds": 900 + }, + "inputs": "{{ inputs.payload }}" + } + }, + "custom_inputs": { + "subject": "str", + "summary": "str", + "approver": "str", + "payload": "json", + "idempotency_key": "str" + }, + "exposed_inputs": [ + "subject", + "summary", + "approver", + "payload", + "idempotency_key" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": { + "approver": "", + "payload": {} + } + }, + { + "node_instance_id": "endpoint", + "node_id": "n_url_builder", + "node_version": "1.0.0", + "title": "Jobs endpoint", + "params": { + "segments": [ + "jobs" + ], + "query": {} + }, + "custom_inputs": {}, + "exposed_inputs": [ + "base" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "submit", + "node_id": "n_http_submit_job", + "node_version": "1.0.0", + "title": "Submit job", + "params": { + "method": "POST", + "job_id_path": "id", + "status_url_path": "status_url", + "poll_after_seconds": 5 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "url", + "headers", + "body" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "poll", + "node_id": "n_http_poll_job", + "node_version": "1.0.0", + "title": "Poll job", + "params": { + "status_path": "status", + "complete_values": [ + "completed" + ], + "failed_values": [ + "failed", + "cancelled", + "rejected", + "expired" + ], + "media_url_path": "url", + "poll_after_seconds": 30, + "max_attempts": 120, + "max_elapsed_seconds": 900 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "remote_job", + "headers" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "endpoint", + "source_output": "url", + "target_node_id": "submit", + "target_input": "url" + }, + { + "source_node_id": "req", + "source_output": "value", + "target_node_id": "submit", + "target_input": "body" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "submit", + "target_input": "headers" + }, + { + "source_node_id": "submit", + "source_output": "remote_job", + "target_node_id": "poll", + "target_input": "remote_job" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "poll", + "target_input": "headers" + } + ], + "graph_inputs": { + "base_url": { + "type": "url", + "required": true, + "default_node": "endpoint", + "default_input": "base" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "hdr", + "default_input": "primary" + }, + "subject": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "subject" + }, + "summary": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "summary" + }, + "approver": { + "type": "str", + "required": false, + "default_node": "req", + "default_input": "approver" + }, + "payload": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "payload" + }, + "idempotency_key": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "idempotency_key" + } + }, + "graph_outputs": { + "decision": { + "node_instance_id": "poll", + "output_name": "response" + }, + "status": { + "node_instance_id": "poll", + "output_name": "status" + }, + "remote_job": { + "node_instance_id": "poll", + "output_name": "remote_job" + } + }, + "metadata": { + "template": { + "category": "pipes", + "status": "mock-only-probe", + "summary": "Human approval requested as a job: submits an approval job and polls until approved, rejected, or expired.", + "composite_interface": { + "inputs": { + "base_url": { + "type": "url", + "required": true, + "default_node": "endpoint", + "default_input": "base" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "hdr", + "default_input": "primary" + }, + "subject": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "subject" + }, + "summary": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "summary" + }, + "approver": { + "type": "str", + "required": false, + "default_node": "req", + "default_input": "approver" + }, + "payload": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "payload" + }, + "idempotency_key": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "idempotency_key" + } + }, + "outputs": { + "decision": { + "type": "json", + "node_instance_id": "poll", + "output_name": "response" + }, + "status": { + "type": "str", + "node_instance_id": "poll", + "output_name": "status" + }, + "remote_job": { + "type": "json", + "node_instance_id": "poll", + "output_name": "remote_job" + } + } + }, + "requires": { + "nodes": [ + "n_coalesce", + "n_http_poll_job", + "n_http_submit_job", + "n_json_template", + "n_url_builder" + ], + "panels": [ + "json" + ], + "capabilities": [ + "public-http", + "async-execution", + "external-write" + ], + "secrets": [] + } + }, + "canvas": { + "positions": { + "hdr": { + "x": 80, + "y": 80 + }, + "req": { + "x": 80, + "y": 300 + }, + "endpoint": { + "x": 80, + "y": 520 + }, + "submit": { + "x": 380, + "y": 80 + }, + "poll": { + "x": 680, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "pipes", + "http", + "automation" + ] +} diff --git a/graphs/pipes/jobs/approval-gate.thumbnail.jpg b/graphs/pipes/jobs/approval-gate.thumbnail.jpg new file mode 100644 index 0000000..5960877 Binary files /dev/null and b/graphs/pipes/jobs/approval-gate.thumbnail.jpg differ diff --git a/graphs/pipes/jobs/job-run.notes.md b/graphs/pipes/jobs/job-run.notes.md new file mode 100644 index 0000000..4467aff --- /dev/null +++ b/graphs/pipes/jobs/job-run.notes.md @@ -0,0 +1,118 @@ +# Job Run + +![Job Run example thumbnail](job-run.thumbnail.jpg) + + + +A reusable submit-and-poll graph for any long-running HTTP job: scoring, verification, +research, builds, or other work that a service runs asynchronously. It builds a job +request, POSTs it to `{base_url}/jobs`, polls the status URL the service returns, and +reports the final status body. It is generic by design and does not know what the job +does. Import it independently, or publish it as a composite. + +This is submit and poll, not scheduling. Each run creates one job. + +**Submitting a job is an externally visible write.** A successful run starts work at +the service, and a retry can start it twice unless the service honors the +idempotency key described below. The graph references no secrets, +environment-specific graph IDs, or generated media. + +## Data flow + +1. **Job request** (`n_json_template`) builds the request body from `kind`, + `idempotency_key`, `params`, and `inputs`. +2. **Jobs endpoint** (`n_url_builder`) appends `jobs` to `base_url`. +3. **Submit job** (`n_http_submit_job`) POSTs the body. It reads the job `id` and the + `status_url` from the response, and uses an optional integer `poll_after_seconds` + hint when the service sends one (5 seconds otherwise). +4. **Poll job** (`n_http_poll_job`) calls the `status_url`, sends the same headers, and + waits between attempts until the status is terminal. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `base_url` | `url` | Required service base URL; the graph posts to `{base_url}/jobs`. Receives the `headers` value | +| `headers` | `json` | Required request headers, built by the parent graph | +| `kind` | `str` | Required job type the service understands | +| `idempotency_key` | `str` | Required key that makes a repeated submission return the same job | +| `params` | `json` | Optional job parameters; defaults to an empty object | +| `inputs` | `json` | Optional job inputs; defaults to an empty object | + +| Output | Type | Meaning | +| --- | --- | --- | +| `result` | `json` | The final status body | +| `status` | `str` | The final status, normalized to lowercase by the poll node | +| `remote_job` | `json` | The resumable job reference | +| `media` | `media` | The media URL from the status body, when the service returns one | + +## Service contract + +The graph works with any HTTP service that follows this shape. + +**Submit.** `POST {base_url}/jobs` with a JSON body holding `kind`, `idempotency_key`, +`params`, and `inputs`. The service answers 200 or 202 with `id`, `status` (normally +`queued`), and `status_url`. It may add an integer `poll_after_seconds` to say how long +to wait before the first poll. A repeated `idempotency_key` should return the existing +job rather than create another, and the same key with different parameters should be +rejected. Put a content version in the key, for example +`::`. + +**Poll.** `GET {status_url}` returns `id`, `status`, `kind`, `url`, `result`, and +`error`. `status` is one of `queued`, `running`, `completed`, `failed`, `cancelled`, +`rejected`, or `expired`. `url` is the media URL once the job completes, and `result` +holds structured output. `error` describes a failure. + +**Terminal handling in this graph.** `completed` ends the poll successfully. `failed` +and `cancelled` count as failures. `rejected` and `expired` are used by approval-style +services; this graph does not list them as failures, so a service that returns them +would be polled until the limits below. Use [Approval Gate](approval-gate.notes.md) +for those, or edit the poll node's failure values. + +## Polling limits + +Polling waits 5 seconds between attempts by default, stops after 120 attempts or 3,600 +seconds. The graph never sends a cancel request, so a job can keep running at the +service after polling stops. + +## Authentication + +The graph never holds a credential. The parent builds the headers from its own secrets +and passes them in: + +1. In the parent, add a JSON Template node with the template + `{"Authorization": "Bearer {{ secrets.JOB_SERVICE_TOKEN }}", "Content-Type": "application/json"}`. +2. Connect its `value` output to this graph's `headers` input. +3. Add the secret `JOB_SERVICE_TOKEN` in the parent graph's **Graph Settings → + Execution Profile**. Never paste a token into a graph, a fixture, or these notes. + +Whether node outputs and execution logs redact header values has not been verified, so +do the first run with a throwaway token and inspect the logs before using a real one. + +## Security guidance + +- **Use a literal `base_url` in the parent graph.** It receives the headers, including + the token. Do not feed it from request data, model output, or any other untrusted + value. +- **Use one low-privilege token per service.** Do not reuse a token across services. +- **Keep `status_url` on the same host as `base_url`.** The poll node calls whatever + `status_url` the service returns, with the same headers. Whether the node enforces a + same-host rule has not been verified, so only point this graph at a service you + control or trust. + +## Using it as a composite + +Publish the graph, pin the version, and call it from a parent that supplies `base_url` +and `headers` as literals or from its own secrets. Keep polling at the top level of the +parent when possible. Connect `result` and `status` to downstream nodes, and `media` to +a media or video preview panel. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. It has not been executed, so it has not been run against a live +job service and no job was submitted. Whether placeholders that stand alone in a template value +(`params` and `inputs`) keep their JSON type has not been confirmed for this graph in a live run. +Whether a poll that reaches a failure status raises a node error or only returns the status has not +been verified either. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/pipes/jobs/job-run.subfork.json b/graphs/pipes/jobs/job-run.subfork.json new file mode 100644 index 0000000..9e70cc6 --- /dev/null +++ b/graphs/pipes/jobs/job-run.subfork.json @@ -0,0 +1,335 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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PM6Mub6iWkZH0KLx2TZvqktVviq+H+kLlYbbcIqyvu1BLKXyTGFgq3NAp5A4djhkPIJOBn0hYZui7eKFtAdOwGwHS5ujtVGOTrRVeDl+4TZ2YE2Iepx/nzWnWVlREYSyeVhhJMRbI4dXk5O3n5uT6l98PqvA/BPCp/BN2/wfrXdVu/tbM4z9OMpvR2LN/wBv4aab1LR0rYLbT0k+pYqe80DoyR4JS07YBXRt59hLqk+v9SFirDR6avFw0LTM0lbHU2qa24slkcyTrIoPCXMhbEQ4BhY3GHYJ5AdnbpRldUx9XtqZm9W1zGbZXDY12dzRz5A5OQO3Jz2r4ysqIjCWTysMGTEWyOHV5OTt5+bz9SnejsWUsY5duPSiIs1hERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARFl7fp91TAyoqZxSwSDLAG75HjOMhuRgcu0kfQpiJq5QiZsxCKRfByg+cKj8K386fByg+cKn8K38609OpXehHUUi+DlB84VP4Vv50+DlB84VP4Vv509Oo3oR1FIvg5QfOFT+Fb+dPg5QfOFT+Fb+dPTqN6EdRSL4OUHzhU/hW/nT4OUHzhU/hW/nT06jehHUUi+DlB84VP4Vv50+DlB84VP4Vv509Oo3oR1FIvg5QfOFT+Fb+dPg5QfOFT+Fb+dPTqN6EdRSL4OUHzhU/hW/nXw6aonDDLjKHegyU2G/bhxP+Sj06jehHkVzX2+a21HVTBuS0Oa5hy17T2EH1K2VJi3KVhERQkRX1stEtz3vD2QQRkB80nYCewADmTy7B/ksp8G6D5wqM/RSj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hGxu3G0Bo7ebcBRp2qao1FPMzStiifBJ1gEdoIDjggBw3cwM5x6wFiJqu7T11ZWOdWNqaxz3VEkYewybjlwO3GQSezsSwnN00TQSaGpK0UtZHU0tolqvGcTWiincyskj2O83Je8EYO70NGCOa1oeRV4RcTTCmPhhpwQepPWdXkZwdvZ6T6PSVR8CqfZpvundygKL+m031rP4goncvlGr+vk/iKlvyVtrKxpijjO9jH+a6Vw7GtB59vaewDKhkkjppHyPOXvcXOP0k5KxxfaGlDyiIudqIiIC9Me6J4exzmPHY5pwR9q8oguPGVZ7XUffO708ZVntdR987vVuim8oXHjKs9rqPvnd6eMqz2uo++d3q3RLyLjxlWe11H3zu9PGVZ7XUffO71bol5Fx4yrPa6j753enjKs9rqPvnd6t0S8i48ZVntdR987vTxlWe11H3zu9W6JeRceMqz2uo++d3p4yrPa6j753erdEvIuPGVZ7XUffO715kramVhZJUzSMPa18riD9hKool5BERQkREQFcC41YAAq6gAegTO71boguPGVZ7XUffO708ZVntdR987vVuim8oXHjKs9rqPvnd6eMqz2uo++d3q3RLyLjxlWe11H3zu9PGVZ7XUffO71bol5Fx4yrPa6j753enjKs9rqPvnd6t0S8i48ZVntdR987vTxlWe11H3zu9W6JeRceMqz2uo++d3p4yrPa6j753erdEvIuPGVZ7XUffO71boigERESIiIK0VZUQM2R1E0bB/2skc0f4Ar14yrPa6j753erdFN5QuPGVZ7XUffO708ZVntdR987vVuiXkXHjKs9rqPvnd6eMqz2uo++d3q3RLyLjxlWe11H3zu9PGVZ7XUffO71bol5Fx4yrPa6j753enjKs9rqPvnd6t0S8i48ZVntdR987vTxlWe11H3zu9W6JeRceMqz2uo++d3p4yrPa6j753erdEvI9SSPmeXyPdI89rnuJP8AiV5RFCRERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERB//2Q==", + "definition": { + "version": "0.1.0", + "name": "Job Run", + "description": "Generic asynchronous job over HTTP. Builds a job request, POSTs it to base_url/jobs (an externally visible write that creates a job), polls the returned status URL until a terminal status, and returns the final status body, the status string, the remote job reference, and the media URL. Credentials arrive only through the headers input. This graph references no secrets.", + "nodes": [ + { + "node_instance_id": "hdr", + "node_id": "n_coalesce", + "node_version": "1.0.0", + "title": "Auth headers fan-out", + "params": { + "fallback": {} + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "req", + "node_id": "n_json_template", + "node_version": "1.0.0", + "title": "Job request", + "params": { + "template": { + "kind": "{{ inputs.kind }}", + "idempotency_key": "{{ inputs.idempotency_key }}", + "params": "{{ inputs.params }}", + "inputs": "{{ inputs.inputs }}" + } + }, + "custom_inputs": { + "kind": "str", + "idempotency_key": "str", + "params": "json", + "inputs": "json" + }, + "exposed_inputs": [ + "kind", + "idempotency_key", + "params", + "inputs" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": { + "params": {}, + "inputs": {} + } + }, + { + "node_instance_id": "endpoint", + "node_id": "n_url_builder", + "node_version": "1.0.0", + "title": "Jobs endpoint", + "params": { + "segments": [ + "jobs" + ], + "query": {} + }, + "custom_inputs": {}, + "exposed_inputs": [ + "base" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "submit", + "node_id": "n_http_submit_job", + "node_version": "1.0.0", + "title": "Submit job", + "params": { + "method": "POST", + "job_id_path": "id", + "status_url_path": "status_url", + "poll_after_seconds": 5 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "url", + "headers", + "body" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "poll", + "node_id": "n_http_poll_job", + "node_version": "1.0.0", + "title": "Poll job", + "params": { + "status_path": "status", + "complete_values": [ + "completed" + ], + "failed_values": [ + "failed", + "cancelled" + ], + "media_url_path": "url", + "poll_after_seconds": 5, + "max_attempts": 120, + "max_elapsed_seconds": 3600 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "remote_job", + "headers" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "endpoint", + "source_output": "url", + "target_node_id": "submit", + "target_input": "url" + }, + { + "source_node_id": "req", + "source_output": "value", + "target_node_id": "submit", + "target_input": "body" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "submit", + "target_input": "headers" + }, + { + "source_node_id": "submit", + "source_output": "remote_job", + "target_node_id": "poll", + "target_input": "remote_job" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "poll", + "target_input": "headers" + } + ], + "graph_inputs": { + "base_url": { + "type": "url", + "required": true, + "default_node": "endpoint", + "default_input": "base" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "hdr", + "default_input": "primary" + }, + "kind": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "kind" + }, + "idempotency_key": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "idempotency_key" + }, + "params": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "params" + }, + "inputs": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "inputs" + } + }, + "graph_outputs": { + "result": { + "node_instance_id": "poll", + "output_name": "response" + }, + "status": { + "node_instance_id": "poll", + "output_name": "status" + }, + "remote_job": { + "node_instance_id": "poll", + "output_name": "remote_job" + }, + "media": { + "node_instance_id": "poll", + "output_name": "media" + } + }, + "metadata": { + "template": { + "category": "pipes", + "status": "mock-only-probe", + "summary": "Generic asynchronous job over HTTP: submit a job request, then poll to a terminal status.", + "composite_interface": { + "inputs": { + "base_url": { + "type": "url", + "required": true, + "default_node": "endpoint", + "default_input": "base" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "hdr", + "default_input": "primary" + }, + "kind": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "kind" + }, + "idempotency_key": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "idempotency_key" + }, + "params": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "params" + }, + "inputs": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "inputs" + } + }, + "outputs": { + "result": { + "type": "json", + "node_instance_id": "poll", + "output_name": "response" + }, + "status": { + "type": "str", + "node_instance_id": "poll", + "output_name": "status" + }, + "remote_job": { + "type": "json", + "node_instance_id": "poll", + "output_name": "remote_job" + }, + "media": { + "type": "media", + "node_instance_id": "poll", + "output_name": "media" + } + } + }, + "requires": { + "nodes": [ + "n_coalesce", + "n_http_poll_job", + "n_http_submit_job", + "n_json_template", + "n_url_builder" + ], + "panels": [ + "json" + ], + "capabilities": [ + "public-http", + "async-execution", + "external-write" + ], + "secrets": [] + } + }, + "canvas": { + "positions": { + "hdr": { + "x": 80, + "y": 80 + }, + "req": { + "x": 80, + "y": 300 + }, + "endpoint": { + "x": 80, + "y": 520 + }, + "submit": { + "x": 380, + "y": 80 + }, + "poll": { + "x": 680, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "pipes", + "http", + "automation" + ] +} diff --git a/graphs/pipes/jobs/job-run.thumbnail.jpg b/graphs/pipes/jobs/job-run.thumbnail.jpg new file mode 100644 index 0000000..3d138ac Binary files /dev/null and b/graphs/pipes/jobs/job-run.thumbnail.jpg differ diff --git a/graphs/pipes/jobs/render-job.notes.md b/graphs/pipes/jobs/render-job.notes.md new file mode 100644 index 0000000..6ec9fb3 --- /dev/null +++ b/graphs/pipes/jobs/render-job.notes.md @@ -0,0 +1,105 @@ +# Render Job + +![Render Job example thumbnail](render-job.thumbnail.jpg) + + + +A reusable asynchronous media job that returns a file. It runs the same submit-and-poll +chain as [Job Run](job-run.notes.md), then reads the artifact location from the +finished job, rebuilds the file URL from the service base URL, and downloads the file as +a Subfork artifact. Use it for video renders, image generation, screenshots, or audio +post-processing that a service performs. Import it independently, or publish it as a +composite. + +**Submitting a job is an externally visible write.** A successful run starts work at the +service, which can be slow and billed. A retry can start it twice unless the service +honors the idempotency key. The graph references no secrets, environment-specific graph +IDs, or generated media. + +## Data flow + +1. **Job request** (`n_json_template`) builds the body from `kind`, `idempotency_key`, + `params`, and `inputs`. +2. **Jobs endpoint** (`n_url_builder`) appends `jobs` to `base_url`. +3. **Submit job** (`n_http_submit_job`) POSTs the body and reads the job `id` and + `status_url`. +4. **Poll job** (`n_http_poll_job`) waits 5 seconds between attempts and stops after 120 + attempts or 3,600 seconds. +5. **Artifact segments** (`n_json_path`) reads `result.artifact_segments` from the final + status body. This is a list of URL path segments. +6. **Artifact file URL** (`n_url_builder`) appends those segments to `base_url`. +7. **Fetch artifact** (`n_fetch_url`) GETs that URL with the same headers and stores the + response as an artifact. The request has a 120-second timeout and a response cap of + 250,000,000 bytes, set explicitly for video. Confirm your instance accepts that + value. + +The file URL is built from `base_url`, never taken whole from the service response, so +the file request goes to the same host as the job request. The service controls only the +path segments. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `base_url` | `url` | Required service base URL. Used for the jobs endpoint and the file URL, and receives the `headers` value | +| `headers` | `json` | Required request headers, built by the parent graph | +| `kind` | `str` | Required job type the service understands, for example a render type | +| `idempotency_key` | `str` | Required key that makes a repeated submission return the same job | +| `params` | `json` | Optional job parameters; defaults to an empty object | +| `inputs` | `json` | Optional job inputs; defaults to an empty object | + +| Output | Type | Meaning | +| --- | --- | --- | +| `artifact` | `artifact` | The downloaded file | +| `media` | `media` | The media URL from the status body, when the service returns one | +| `result` | `json` | The final status body | +| `status` | `str` | The final status, normalized to lowercase by the poll node | + +The service contract is the one described in [Job Run](job-run.notes.md), with one +addition: when a job completes, `result.artifact_segments` must hold the path segments of +the output file relative to the service base URL, and the file must be served from the +same host and accept the same headers. Put a content version in the idempotency key, for +example `::`. + +## Authentication + +The graph never holds a credential. The parent builds the headers from its own secrets +and passes them in: + +1. In the parent, add a JSON Template node with the template + `{"Authorization": "Bearer {{ secrets.JOB_SERVICE_TOKEN }}", "Content-Type": "application/json"}`. +2. Connect its `value` output to this graph's `headers` input. +3. Add the secret `JOB_SERVICE_TOKEN` in the parent graph's **Graph Settings → + Execution Profile**. Never paste a token into a graph, a fixture, or these notes. + +The same headers are sent on the submit, poll, and file requests. Whether node outputs +and execution logs redact header values has not been verified, so do the first run with a +throwaway token and inspect the logs before using a real one. + +## Security guidance + +- **Use a literal `base_url` in the parent graph.** It receives the headers, including + the token, on all three requests. Do not feed it from request data, model output, or + any other untrusted value. +- **Use one low-privilege token per service.** Do not reuse a token across services. +- **Keep `status_url` on the same host as `base_url`.** The poll node calls whatever + `status_url` the service returns, with the same headers. Whether the node enforces a + same-host rule has not been verified, so only point this graph at a service you + control or trust. +- **Trust what the service renders.** Some services run project code or templates that + you supply. Point the service only at inputs you control. + +## Using it as a composite + +Publish the graph, pin the version, and call it from a parent that supplies `base_url` +and `headers`. Connect `artifact` to storage or an upload step, and `media` to a Video or +Media Preview panel. Keep polling at the top level of the parent when possible. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. It has not been executed, so it has not been run against a live +job service, no job was submitted, and no file was downloaded. Whether the platform accepts the +250,000,000 byte response cap, and whether a poll that reaches a failure status raises a node error +or only returns the status, have not been verified. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/pipes/jobs/render-job.subfork.json b/graphs/pipes/jobs/render-job.subfork.json new file mode 100644 index 0000000..5f9b99b --- /dev/null +++ b/graphs/pipes/jobs/render-job.subfork.json @@ -0,0 +1,460 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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", + "definition": { + "version": "0.1.0", + "name": "Render Job", + "description": "Asynchronous media job over HTTP. Submits a job (an externally visible write), polls until it completes, reads result.artifact_segments from the final status body, rebuilds the file URL from base_url plus those segments, and fetches the file as an artifact with the same headers. Credentials arrive only through the headers input. This graph references no secrets.", + "nodes": [ + { + "node_instance_id": "base_in", + "node_id": "n_url_input", + "node_version": "1.0.0", + "title": "Service base URL", + "params": { + "url": "https://example.com" + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "hdr", + "node_id": "n_coalesce", + "node_version": "1.0.0", + "title": "Auth headers fan-out", + "params": { + "fallback": {} + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "req", + "node_id": "n_json_template", + "node_version": "1.0.0", + "title": "Job request", + "params": { + "template": { + "kind": "{{ inputs.kind }}", + "idempotency_key": "{{ inputs.idempotency_key }}", + "params": "{{ inputs.params }}", + "inputs": "{{ inputs.inputs }}" + } + }, + "custom_inputs": { + "kind": "str", + "idempotency_key": "str", + "params": "json", + "inputs": "json" + }, + "exposed_inputs": [ + "kind", + "idempotency_key", + "params", + "inputs" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": { + "params": {}, + "inputs": {} + } + }, + { + "node_instance_id": "endpoint", + "node_id": "n_url_builder", + "node_version": "1.0.0", + "title": "Jobs endpoint", + "params": { + "segments": [ + "jobs" + ], + "query": {} + }, + "custom_inputs": {}, + "exposed_inputs": [ + "base" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "submit", + "node_id": "n_http_submit_job", + "node_version": "1.0.0", + "title": "Submit job", + "params": { + "method": "POST", + "job_id_path": "id", + "status_url_path": "status_url", + "poll_after_seconds": 5 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "url", + "headers", + "body" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "poll", + "node_id": "n_http_poll_job", + "node_version": "1.0.0", + "title": "Poll job", + "params": { + "status_path": "status", + "complete_values": [ + "completed" + ], + "failed_values": [ + "failed", + "cancelled" + ], + "media_url_path": "url", + "poll_after_seconds": 5, + "max_attempts": 120, + "max_elapsed_seconds": 3600 + }, + "custom_inputs": {}, + "exposed_inputs": [ + "remote_job", + "headers" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "path", + "node_id": "n_json_path", + "node_version": "1.0.0", + "title": "Artifact segments", + "params": { + "path": "result.artifact_segments" + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "file_url", + "node_id": "n_url_builder", + "node_version": "1.0.0", + "title": "Artifact file URL", + "params": { + "query": {} + }, + "custom_inputs": {}, + "exposed_inputs": [ + "base", + "segments" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "fetch", + "node_id": "n_fetch_url", + "node_version": "1.0.0", + "title": "Fetch artifact", + "params": { + "method": "GET", + "timeout_seconds": 120, + "max_response_bytes": 250000000, + "response_storage": "artifact" + }, + "custom_inputs": {}, + "exposed_inputs": [ + "url", + "headers" + ], + "inputs_visibility_configured": true, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "base_in", + "source_output": "url", + "target_node_id": "endpoint", + "target_input": "base" + }, + { + "source_node_id": "endpoint", + "source_output": "url", + "target_node_id": "submit", + "target_input": "url" + }, + { + "source_node_id": "req", + "source_output": "value", + "target_node_id": "submit", + "target_input": "body" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "submit", + "target_input": "headers" + }, + { + "source_node_id": "submit", + "source_output": "remote_job", + "target_node_id": "poll", + "target_input": "remote_job" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "poll", + "target_input": "headers" + }, + { + "source_node_id": "base_in", + "source_output": "url", + "target_node_id": "file_url", + "target_input": "base" + }, + { + "source_node_id": "poll", + "source_output": "response", + "target_node_id": "path", + "target_input": "value" + }, + { + "source_node_id": "path", + "source_output": "value", + "target_node_id": "file_url", + "target_input": "segments" + }, + { + "source_node_id": "file_url", + "source_output": "url", + "target_node_id": "fetch", + "target_input": "url" + }, + { + "source_node_id": "hdr", + "source_output": "value", + "target_node_id": "fetch", + "target_input": "headers" + } + ], + "graph_inputs": { + "base_url": { + "type": "url", + "required": true, + "default_node": "base_in", + "default_param": "url" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "hdr", + "default_input": "primary" + }, + "kind": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "kind" + }, + "idempotency_key": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "idempotency_key" + }, + "params": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "params" + }, + "inputs": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "inputs" + } + }, + "graph_outputs": { + "artifact": { + "node_instance_id": "fetch", + "output_name": "artifact" + }, + "media": { + "node_instance_id": "poll", + "output_name": "media" + }, + "result": { + "node_instance_id": "poll", + "output_name": "response" + }, + "status": { + "node_instance_id": "poll", + "output_name": "status" + } + }, + "metadata": { + "template": { + "category": "pipes", + "status": "mock-only-probe", + "summary": "Asynchronous media job that returns a file: runs the job chain, rebuilds the file URL, fetches the artifact.", + "composite_interface": { + "inputs": { + "base_url": { + "type": "url", + "required": true, + "default_node": "base_in", + "default_param": "url" + }, + "headers": { + "type": "json", + "required": true, + "default_node": "hdr", + "default_input": "primary" + }, + "kind": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "kind" + }, + "idempotency_key": { + "type": "str", + "required": true, + "default_node": "req", + "default_input": "idempotency_key" + }, + "params": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "params" + }, + "inputs": { + "type": "json", + "required": false, + "default_node": "req", + "default_input": "inputs" + } + }, + "outputs": { + "artifact": { + "type": "artifact", + "node_instance_id": "fetch", + "output_name": "artifact" + }, + "media": { + "type": "media", + "node_instance_id": "poll", + "output_name": "media" + }, + "result": { + "type": "json", + "node_instance_id": "poll", + "output_name": "response" + }, + "status": { + "type": "str", + "node_instance_id": "poll", + "output_name": "status" + } + } + }, + "requires": { + "nodes": [ + "n_coalesce", + "n_fetch_url", + "n_http_poll_job", + "n_http_submit_job", + "n_json_path", + "n_json_template", + "n_url_builder", + "n_url_input" + ], + "panels": [ + "json" + ], + "capabilities": [ + "public-http", + "async-execution", + "artifact-storage", + "external-write" + ], + "secrets": [] + } + }, + "canvas": { + "positions": { + "base_in": { + "x": 80, + "y": 80 + }, + "hdr": { + "x": 80, + "y": 300 + }, + "req": { + "x": 80, + "y": 520 + }, + "endpoint": { + "x": 380, + "y": 80 + }, + "submit": { + "x": 680, + "y": 80 + }, + "poll": { + "x": 980, + "y": 80 + }, + "path": { + "x": 1280, + "y": 80 + }, + "file_url": { + "x": 1580, + "y": 80 + }, + "fetch": { + "x": 1880, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "pipes", + "http", + "rendering" + ] +} diff --git a/graphs/pipes/jobs/render-job.thumbnail.jpg b/graphs/pipes/jobs/render-job.thumbnail.jpg new file mode 100644 index 0000000..44f17b6 Binary files /dev/null and b/graphs/pipes/jobs/render-job.thumbnail.jpg differ diff --git a/graphs/pipes/transforms/fallback-match.notes.md b/graphs/pipes/transforms/fallback-match.notes.md new file mode 100644 index 0000000..56484f1 --- /dev/null +++ b/graphs/pipes/transforms/fallback-match.notes.md @@ -0,0 +1,70 @@ +# Fallback Match + +![Fallback Match example thumbnail](fallback-match.thumbnail.jpg) + + + +A reusable exact-key join that returns a recorded fixture when the join finds nothing. +It left-joins two lists of records on a key, and falls back to a value the caller +supplies when the result is empty. Use it for a library or feed lookup that should still +produce something predictable when the live data has no match. Import it independently, +or publish it as a composite. + +Matching is exact on the key values. Tolerance or fuzzy joins are not covered. The graph +is local JSON processing: it makes no network requests, needs no credentials, and has no +side effects. + +## Data flow + +1. **Exact-key join** (`n_join_records`) left-joins `left` and `right` on `left_key` and + `right_key`. Both keys default to `id`. +2. **Join or recorded fixture** (`n_coalesce`) returns the join result, or `fixture` when + the join yields nothing. + +## Inputs and outputs + +| Input | Type | Meaning | +| --- | --- | --- | +| `left` | `json` | Required list of records that drive the result | +| `right` | `json` | Required list of records to look up | +| `fixture` | `json` | Required fallback value returned when the join is empty | +| `left_key` | `str` | Optional field name in `left`; defaults to `id` | +| `right_key` | `str` | Optional field name in `right`; defaults to `id` | + +| Output | Type | Meaning | +| --- | --- | --- | +| `items` | `json` | The joined records, or the fixture | + +Because the join is a left join, every `left` record appears in the result even without +a match. A run with records in `left` and an empty `right` returned the `left` records with `right` +null and did not use the fixture. Whether the fallback node treats an empty list as empty, and so +returns the fixture, has not been confirmed. Run the graph once with an empty `left` list and check +whether the output is the fixture before depending on the fallback. + +## Authentication and security + +There is nothing to wire. The graph holds no credentials and calls no service. The +fixture is returned as given, so keep real data and secrets out of it if the output is +displayed or sent onward. + +## Using it as a composite + +Publish the graph and call it from a parent that fetches `left` and `right` upstream and +passes a small recorded `fixture` shaped like the real result. Connect `items` to the +next transform or a table or JSON panel. + +## Validation status + +The graph passes the repository validator and the node-catalog check against the production catalog, and the Subfork server-side validate endpoint (`POST /graphs/validate`) accepted it on 2026-11-05. + +It was imported and executed twice on subfork.com on 2026-11-05 by anthonyshafer@gmail.com, using +fixture inputs only and no network, and both runs completed. In the first, `left` had two records +and `right` had one match; the unmatched record came back with `right` null and the fixture was not +used. In the second, `left` had one record and `right` was empty; the record came back with `right` +null and the fixture was again not used. Neither run produced an empty join, so the fallback +itself has not been exercised. Whether an empty `left` list returns the fixture is still +unconfirmed; run it before depending on the fallback. Its nodes, edges, and graph inputs and +outputs match this file; the test runs set the fallback value on the coalesce node instead of +passing it through the `fixture` input. + +No Subfork platform version could be found on the public API or site, so this note records the check date and the node catalog instead: on 2026-11-05 the catalog served 75 node types, and every node in this graph is version `1.0.0`. diff --git a/graphs/pipes/transforms/fallback-match.subfork.json b/graphs/pipes/transforms/fallback-match.subfork.json new file mode 100644 index 0000000..d37cfe5 --- /dev/null +++ b/graphs/pipes/transforms/fallback-match.subfork.json @@ -0,0 +1,163 @@ +{ + "format": "subfork.graph/1", + "thumbnail": "data:image/jpeg;base64,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", + "definition": { + "version": "0.1.0", + "name": "Fallback Match", + "description": "Exact-key join with a recorded fallback. Left-joins left and right on the given keys and returns the joined items, or the fixture value when the join yields nothing. Tolerance joins are not covered. No network, no credentials.", + "nodes": [ + { + "node_instance_id": "join", + "node_id": "n_join_records", + "node_version": "1.0.0", + "title": "Exact-key join", + "params": { + "left_key": "id", + "right_key": "id", + "mode": "left" + }, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + }, + { + "node_instance_id": "pick", + "node_id": "n_coalesce", + "node_version": "1.0.0", + "title": "Join or recorded fixture", + "params": {}, + "custom_inputs": {}, + "exposed_inputs": [], + "inputs_visibility_configured": false, + "exposed_outputs": null, + "outputs_visibility_configured": false, + "literal_inputs": {} + } + ], + "edges": [ + { + "source_node_id": "join", + "source_output": "items", + "target_node_id": "pick", + "target_input": "primary" + } + ], + "graph_inputs": { + "left": { + "type": "json", + "required": true, + "default_node": "join", + "default_input": "left" + }, + "right": { + "type": "json", + "required": true, + "default_node": "join", + "default_input": "right" + }, + "fixture": { + "type": "json", + "required": true, + "default_node": "pick", + "default_param": "fallback" + }, + "left_key": { + "type": "str", + "required": false, + "default_node": "join", + "default_param": "left_key" + }, + "right_key": { + "type": "str", + "required": false, + "default_node": "join", + "default_param": "right_key" + } + }, + "graph_outputs": { + "items": { + "node_instance_id": "pick", + "output_name": "value" + } + }, + "metadata": { + "template": { + "category": "pipes", + "status": "mock-only-probe", + "summary": "Exact-key left join that returns a recorded fixture when the join is empty.", + "composite_interface": { + "inputs": { + "left": { + "type": "json", + "required": true, + "default_node": "join", + "default_input": "left" + }, + "right": { + "type": "json", + "required": true, + "default_node": "join", + "default_input": "right" + }, + "fixture": { + "type": "json", + "required": true, + "default_node": "pick", + "default_param": "fallback" + }, + "left_key": { + "type": "str", + "required": false, + "default_node": "join", + "default_param": "left_key" + }, + "right_key": { + "type": "str", + "required": false, + "default_node": "join", + "default_param": "right_key" + } + }, + "outputs": { + "items": { + "type": "json", + "node_instance_id": "pick", + "output_name": "value" + } + } + }, + "requires": { + "nodes": [ + "n_coalesce", + "n_join_records" + ], + "panels": [ + "json" + ], + "capabilities": [], + "secrets": [] + } + }, + "canvas": { + "positions": { + "join": { + "x": 80, + "y": 80 + }, + "pick": { + "x": 380, + "y": 80 + } + }, + "recommended_panels": [] + } + } + }, + "tags": [ + "pipes", + "transforms" + ] +} diff --git a/graphs/pipes/transforms/fallback-match.thumbnail.jpg b/graphs/pipes/transforms/fallback-match.thumbnail.jpg new file mode 100644 index 0000000..15f3544 Binary files /dev/null and b/graphs/pipes/transforms/fallback-match.thumbnail.jpg differ