Visual workflows turn analysis routines into reproducible graphs. Every block receives typed artifacts, produces new artifacts and records duration, inputs, outputs, hashes and versions.
Get started #
- Open Settings → Extensions → Workflows.
- Install the laboratory templates and open a workflow.
- Review its approval and run the fixture.
- Tap the output of a step and then the input of the next one; only compatible types are accepted.
A condition offers true and false routes, and a join waits for the selected inputs. Drag, zoom, arrange or duplicate blocks. The properties panel sits on the side on larger screens and at the bottom on phones.
Block types #
| Block | Role |
|---|---|
capture | captured traffic input |
filter | selects artifacts |
condition | splits the flow into true and false |
join | merges branches |
parser | interprets content by MIME type |
request | sends approved requests |
crawler | walks pages with GET and HEAD |
storage | persists results |
report | consolidates a report |
connector | runs a CatBridge capability |
extension | runs a step registered by an extension |
Artifacts #
| Type | Typical content |
|---|---|
http | complete HTTP message |
endpoint | observed URL, with origin |
jwt | decoded claims, without signature verification |
secret | masked secret candidate |
analysis | structured analysis |
finding | finding with severity and confidence |
record | generic record |
javascript | static JavaScript source |
openapi | OpenAPI specification |
The host generates identity, SHA-256, origin, versions, sources and protection for every artifact. Copying an input creates new evidence linked to the previous one, and metadata provided by the script never replaces the host’s.
Register steps and parsers #
cat.pipeline.registerStep({
id: 'lab.inspect',
title: {'pt-BR': 'Inspecionar', en: 'Inspect'},
inputs: ['http'],
outputs: ['http', 'analysis']
}, async ctx => {
for (const input of ctx.inputs) {
if (ctx.signal.aborted) return;
ctx.emit('http', input.data);
ctx.emit('analysis', {url: input.data.url, confidence: 'observed'});
}
ctx.progress(1);
});
cat.parsers.register({
id: 'lab.json',
title: {'pt-BR': 'Ler JSON', en: 'Parse JSON'},
inputs: ['http'],
outputs: ['record'],
mimeTypes: ['application/json']
}, ctx => {
for (const input of ctx.inputs) {
if (!input.data.body.complete) throw new Error('E_BODY');
ctx.emit('record', JSON.parse(cat.bytes.toText(input.data.body.bytes)));
}
});Declare pipeline.step or parsers in the manifest and, to receive HTTP, also traffic.read. Only declared types can be emitted.
Step context #
| Field | Description |
|---|---|
ctx.inputs | input artifacts |
ctx.config | the step’s own configuration |
ctx.runId, ctx.nodeId | run and block identity |
ctx.revisionId | approved revision being executed |
ctx.protection | PUBLIC, PROTECTED or SECRET |
ctx.restored | state from the last checkpoint |
ctx.checkpoint(state) | stores up to 32 KiB of JSON |
ctx.emit(type, data) | emits an artifact |
ctx.progress(value) | progress from 0 to 1 |
ctx.signal.aborted | signals cancellation |
Checkpoints and resuming #
cat.pipeline.registerStep({
id: 'lab.resume',
title: {'pt-BR': 'Retomar', en: 'Resume'},
inputs: ['record'],
outputs: ['record']
}, async ctx => {
let done = ctx.restored?.done || 0;
for (; done < ctx.inputs.length; done++) {
if (ctx.signal.aborted) return;
ctx.emit('record', ctx.inputs[done].data);
await ctx.checkpoint({done: done + 1});
}
});Results, operations and checkpoints are written incrementally. Resuming reuses completed steps. An operation with an unknown outcome is never resent automatically; retrying it requires explicit authorization after reviewing possible duplicated effects. Checkpoints do not make external transactions idempotent by themselves.
Approval and revisions #
The Flow ID is permanent. The revision is the SHA-256 of the executable definition, dependencies and effective policy; name and visual position are not part of that hash. Saving or exporting without executable changes keeps the activation. Changing code, settings, scope, methods, protection, capabilities or limits requires new approval, and previous revisions are archived.
Sends require network=true, a run with sends enabled, an allowed destination and a matching capability. Generated traffic has source=workflow, flowOrigin and pluginOrigin, and never restarts the workflow.
Failures and history #
- A failure blocks its dependents; independent branches may still finish.
- A branch that was not chosen is skipped.
- History shows duration, progress, inputs, outputs, errors, hashes and versions.
- Comparison highlights added or removed results and version changes.
- Replaying creates a new run that starts without network access.
Limits #
| Resource | Default | Ceiling |
|---|---|---|
| Concurrent workflows | 2 | 4 |
| Blocks per workflow | 32 | 128 |
| Connections | 64 | 256 |
| Queue | 128 | 512 |
| Artifacts per run | 1,000 | 5,000 |
Analyses use two 32 MiB environments, separate from the four proxy environments. A run lasts up to 15 minutes and connector tasks up to 10 minutes. Saturation is recorded and never suspends proxy forwarding.
Included templates #
| Template | Steps |
|---|---|
| Identity audit | Capture → JWT → Secrets → Authorization → Report |
| API map | Crawler → JavaScript → Endpoints → OpenAPI → Report |
| Branches | Condition on Authorization, JWT and secrets branches, join and report |
| API audit | Capture → httpx → Katana → join → OpenAPI comparison → Schemathesis → report |