Skip to Content
kusaw docsv1.0.0

Outside classify (example)

This page is a stub. The factory has no outside classify provider and makes no network call for routing. `routing.classify.provider` stays `agent`, `command`, or `off`. A user who accepts an outside typed-decision service writes their own [command](workflows.md) classifier; the factory ships the pattern, not the path.

This page is a stub. The factory has no outside classify provider and makes no network call for routing. routing.classify.provider stays agent, command, or off. A user who accepts an outside typed-decision service writes their own command classifier; the factory ships the pattern, not the path.

Warnings

  • The item's title, type, labels, and source leave the machine. If you turn on the body, that text leaves too.
  • The factory does not check or warn about this. It cannot tell whether a command classifier calls an outside service.
  • This example is not allowed in setups where nothing may go to outside services or cloud runners.
  • To keep classify on the machine, set routing.classify.provider: agent (or off). Do not merge this fragment.

What this is

examples/routing/outside-classifier/ is a small Go program (standard library only, CGO_ENABLED=0). It speaks protocol v2 mode: "classify" the same way as any custom step: handshake, request on stdin, result with outputs: {workflow, confidence, rationale}. It uses that step's declared secrets (DEMO_DECIDE_TOKEN: {secret: true}).

The JSON it sends and the JSON it expects back are placeholders for a generic typed-decision API. Change BuildRequest and MapAnswer for a real service. No vendor is named or shipped. The demo URL is https://decide.example.invalid/v1/decide.

Config fragment

Merge this into kusaw.yaml. provider is command, not outside. There is no routing.classify.outside block and no allow_outside_service key; kusaw validate rejects those as unknown values or unknown keys.

YAML
steps:
  route-classify:
    command: ["./bin/outside-classifier"]
    env:
      DEMO_DECIDE_URL: { value: "https://decide.example.invalid/v1/decide" }
      DEMO_DECIDE_TOKEN: { secret: true }
      DEMO_DECIDE_SEND_BODY: { value: "0" }            # 1 to send the body (opt-in)
      DEMO_DECIDE_NEVER_SEND_LABELS: { value: "confidential" }

routing:
  classify:
    provider: command
    step: route-classify
    threshold: 0.80

Build with CGO_ENABLED=0 go build -o bin/outside-classifier ./examples/routing/outside-classifier.

What is sent

By default the program sends title, type, labels, and source only. The body is sent only with DEMO_DECIDE_SEND_BODY=1, cut to 4,000 characters. Repo names, paths, run data, and secrets are never read from the request into the outgoing body.

The outgoing JSON looks like {"choices": [{"id", "description"}], "input": {...}}. The token goes as a Authorization: Bearer header, not in the body.

Never-send

Items that must stay local are not sent:

  • a label listed in DEMO_DECIDE_NEVER_SEND_LABELS (comma-separated; the fragment lists confidential)
  • a source listed in DEMO_DECIDE_NEVER_SEND_SOURCES (comma-separated; a trailing * is a prefix, so inbox:* matches inbox:bugs)

The program answers confidence 0 with rationale not sent: never-send rule. Below the classify threshold, or on a classify failure, the task waits for you to pick a workflow.

Redaction

Secret-looking values are replaced with [REDACTED] before send. The public patterns are:

  • Bearer or Basic tokens: (?i)\b(?:bearer|basic) [A-Za-z0-9\-._~+/=]{8,}
  • JWT: eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+
  • User and password in a URL: ([a-zA-Z][a-zA-Z0-9+.-]*://)([^@/\s:]+):([^@/\s]+)@
  • Key or token query parameters: (?i)([?&](?:api[_-]?key|token|secret|password|access_key)=)[^&\s#]+
  • Email addresses: [A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}
  • Long hex strings (32+): \b[0-9a-fA-F]{32,}\b
  • Long base64 strings (40+): \b[A-Za-z0-9+/]{40,}={0,2}

Redaction is not a guarantee. Do not send work you are not willing to leave the machine.

Failures and waiting

The HTTP call has a 2-second timeout and one retry after 1 second on timeout, a network error, 429, or 5xx. After that, and when the answer names a choice not in the workflow list or a confidence outside 0 to 1, the program answers confidence 0 with rationale outside service failed: <problem> so the task waits.

The program writes no item text to stderr or logs. The rationale lists the field names sent (not their values) and the host, so the routing record shows that an outside service was asked.

Try it

-dry-run prints the JSON body it would send (the bearer token is not in that body) and exits without sending. Point stdin at a protocol v2 classify request:

Text
./bin/outside-classifier -dry-run < request.json

To exercise routing without adding a task, merge the fragment, build the binary, and run:

Text
kusaw routing test specs/demo.md --classify

Use -dry-run on the command (command: ["./bin/outside-classifier", "-dry-run"]) when you only want to see the body; that mode does not classify.

On this page