Skip to content

Releases: ucsandman/declick

declick 0.6.0

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31

Five answers to the same problem, that an API sends more than the agent asked for and the whole of it lands in the context, plus warm MCP servers so the second call stops paying the first one's startup. The savings are measured: scripts/bench-tokens.mjs against nine real MCP servers (258 tools) puts the raw tool listing at 236,818 bytes and declick describe at 58,309, a 4.1x reduction (docs/bench.md). 631 tests pass.

  • --where k=v on any verb filters a list before --fields and --limit, so rows are narrowed on the machine that has them. Repeatable, comma-separable, dotted paths, and eight operators: k=v, k!=v, k~re (case-insensitive regex), k>n, k>=n, k<n, k<=n, and k=* for present and not null. A number compares as a number and a bool as a bool; everything else is an exact string match, and a row with no value at the path fails the condition instead of stopping the run. meta.where is {matched, of} and meta.count is what matched. A condition alone unwraps the rows inside a response object the way --fields does. A condition on a verb that answers with one object is exit 1 naming the verb.
  • A default ceiling on what one envelope carries: 8192 bytes of data, moved by DECLICK_MAX_BYTES or per call by --max-bytes N, and turned off with 0. It applies after --where, --rows, --fields and --limit, and never to --dry-run, --help or describe. A list drops tail rows and keeps at least one, a string is sliced, and an object keeps every key with its biggest values replaced by <N bytes; add --fields or --limit>, so the shape needed to write a --fields survives any cap. meta.truncated is true and meta.capped is {bytes, max, hint}; the exit code stays 0. A --each batch is held to the cap per item and never as a whole, since every entry is the record of a run that happened; a capped item carries its own capped.
  • --cache <seconds> on a read-only verb answers from the response the wire already gave. Entries live in ~/.declick/<name>/cache/ keyed on the adapter, the verb, its positional args and its own flags, so the same call shaped two ways reads one stored response. A hit skips the engine and reports meta.cache {hit: true, age}; a miss stores only a result that worked and reports {hit: false, stored: true}. The local policy still decides on a hit. --cache on a mutating verb is exit 1 naming the verb, --dry-run neither reads nor writes, --cache 0 and DECLICK_CACHE=off bypass it, and declick build and declick remove clear it. A defaults file may set it per verb.
  • declick audit --sum adds the run log up instead of listing it: one row per adapter and one total, sorted by bytes read. Every audit line now carries bytes, the size of the envelope that run wrote to stdout, beside ms, so 212 calls, 340.2 KB read through adapters, 3 failed answers what the adapters actually cost. --adapter, --since and --failed narrow the sum the way they narrow the lines; a line written before bytes existed counts as 0 rather than dropping the run. A run that asked for a cache records cache: hit or cache: miss.
  • where, max-bytes and cache are reserved flag names now: a verb parameter called any of them is renamed param-<name> on the next build.
  • The DashClaw guard has a contract test: test/fixtures/dashclaw-guard-schema.json is DashClaw's guard input schema, test/guard-contract.test.mjs validates what guardBody() sends against it, and npm run qa posts one real body to $DASHCLAW_URL when a key is set. The 0.5.1 wire-format bug survived 566 tests because every guard test was a mock.
  • Warm MCP servers. declick daemon start|stop|status runs a detached per-user process that keeps stdio MCP servers alive between calls, so only the first declick run <mcp adapter> <verb> pays the server's startup instead of every one of them. A run tries the daemon with a 300 ms connect budget and falls back to spawning its own server when nothing answers, so nothing breaks when it is not up; a served run carries meta.daemon: true. Servers are pooled per adapter and per what it was spawned from, dropped after DECLICK_DAEMON_IDLE_MS (default 600000) idle, and the daemon exits once it has had none for the same window. The endpoint is per user (a named pipe on Windows, ~/.declick/daemon.sock at 0600 elsewhere), every message carries the token in ~/.declick/daemon.json (0600), and a daemon.json whose pid is gone counts as no daemon. declick doctor reports it. HTTP MCP adapters are untouched, and the guard, the local policy and the audit line stay on the client side of the socket.

Install: npm i -g declick@0.6.0 · npm · declick.dev

declick 0.5.1

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31

The DashClaw guard call now matches what a current DashClaw (5.31) accepts. Found by running strict mode against a real instance, which answered 401 to every call.

  • The key is sent as x-api-key. DashClaw reads Authorization: Bearer as an OAuth token, so an oc_live key sent that way was "invalid token" and strict mode blocked every mutating verb.
  • The body is DashClaw's guard input: action_type (with action kept as the alias), agent_id and agent_name of declick, declared_goal (declick run <adapter> <verb>), risk_score, target, systems_touched (the target host), and a tool object carrying the adapter name, engine, method and redacted args, where a policy can match on them. The flat {tool, action, method, args} shape was silently stripped by the validator and refused with tool must be an object.
  • The call is /api/guard?record=true, so every decision becomes an action record on the DashClaw dashboard, and decision_id or action_id is accepted as the approval id when the guard asks for one.
  • Tests, README and the site describe the new shape. 566 tests pass, qa 40 of 40.

Install: npm i -g declick@0.5.1 · npm · declick.dev

declick 0.5.0

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31

Every item the 0.3.0 gap audit deferred except the macOS/Linux desktop backend. 566 tests pass.

  • compose, a tenth engine: a chain of verbs from adapters you already built becomes one verb with one envelope, so an agent stops re-deriving the same two or three calls every session. declick add compose:./chain.json --name ops, or declick compose ops --steps ./chain.json (- reads stdin and keeps a copy the adapter owns, so declick build ops still works); declick compose ops prints the chain step by step. A chain file is {"compose": true, "verbs": [{name, description, args, flags, steps, returns}]}; a step is {"run": "<adapter> <verb> {arg}", "as": "name", "optional": false} with run a shell-style string or an argv array. Templates read the composite's arguments and flags ({id}) and earlier steps' data ({pet.owner.name}). Every step runs as its own declick command in a child process, so it keeps its own governance decision, credentials, flag defaults and audit line; a mutating chain is put to DashClaw once for the composite and once per mutating step. declick add refuses a chain naming an adapter or verb that is not there, a template that names nothing, or a returns that points at no step. A failing step stops the chain with that step's exit code and step <i> (<adapter> <verb>): <error>, with data.steps carrying everything that already ran; --dry-run previews every step and sends nothing; a chain that calls itself stops at eight levels deep.
  • --each <file|-> on any verb: run it once per item in a file of inputs, sequentially, and get one envelope back. NDJSON, a JSON array, or stdin; an item is {"args": [...], "flags": {...}} or a flat object of the verb's arg and flag names. Command-line args and flags are the default for every item and the item overrides per key, except --dry-run, which an item may turn on and never off. data is one entry per item (input, ok, exit, data or error) in input order, each shaped by its own --fields, --limit and --rows; meta carries count, failed and each: true. Every item is guarded on its own; a failing item does not stop the rest, a blocked item does (the entries behind it read not run: item N was blocked, exit 3). Exit 0 when every item is ok, otherwise the first failing item's code. A missing file, a line that is not JSON or an item that is neither shape is exit 1 naming the line, and nothing runs.
  • Per-adapter flag defaults in ~/.declick/<name>/defaults.json: {"*": {"limit": 20, "fields": "id,name"}, "find-pets-by-status": {"status": "sold"}}. The * scope applies to every verb, a verb scope wins over *, a flag typed on the command line wins over both; values are parsed exactly like the tokens they stand for. meta.defaults lists the keys a run took from the file and declick describe prints them on one line. The file sits beside manifest.json, so declick build never clobbers it. A key the verb does not accept is exit 1 naming the file and the key; a file that is not valid JSON is exit 1 naming the --clear that fixes it, and leaves describe, lint and build working. declick defaults <name> [--verb v] [--set k=v] [--unset k] [--clear] [--dry-run] prints or edits it, and every --set is checked against the flags that scope accepts. --no-defaults and DECLICK_DEFAULTS=off skip the file.
  • policy.json: a local per-verb policy that needs no service. $DECLICK_HOME/policy.json (or DECLICK_POLICY) holds rules, each an adapter glob, a verb glob, an optional mutating filter, a decision of allow, warn or block and an optional reason. First match wins; no file and no match are both allow. A block is exit 3 with blocked by policy: <reason> before anything is sent, including on read-only verbs, which never reached the guard before. A warn writes one stderr line and runs, and still defers to DashClaw when a key is set. --dry-run never consults it. The file fails closed: unreadable JSON, a bad decision, a rules that is not an array or an unknown field makes every run exit 1 naming the file. declick policy [--check <adapter> <verb>] [--example] shows the rules, which one wins for a verb, and an example file. meta.governance.source is "policy" when the local file decided, on the envelope and the audit line.
  • declick web text <url> [--selector css] [--grep re] [--limit N]: the page's visible text as numbered lines, so "does the page say X" is one call with an exit code (2 when nothing matches) instead of a page dump. declick web tree takes the same --grep, tested against role:name and href. The setup rules block and the Claude Code hook now point at it instead of curl | grep -c.
  • An openapi verb whose response is text/event-stream is read as it arrives instead of buffered whole: data is an array of parsed events ({event?, id?, data}, JSON payloads parsed) and meta.stream carries {events, complete, truncatedByTimeout, ms}. When the timeout budget runs out mid-stream, the events already received come back with meta.truncated: true and exit 0 instead of a timeout with nothing.
  • declick setup never overwrites an adapter that already exists under the name it would pick: a server whose plain name collides falls back to <name>-mcp only when that name is free, otherwise it is skipped naming the adapter and its source. A bearer needed on the fallback attempt is reported as needs <TOKEN> in the vault, not as a collision. The bin dir lands on the running process's PATH once installed, so setup no longer prints add to PATH once for every adapter it builds.
  • The runtime's per-invocation work (flag check, policy, governance, credential scoping, the engine call) moved into one function, so --each and compose steps run the identical path. No change to what a single run answers. each and defaults are reserved flag names now: a verb parameter called either is renamed param-each / param-defaults on the next build.

Install: npm i -g declick@0.5.0 · npm · declick.dev

declick 0.4.1

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31
  • The standalone revert.mjs in a setup snapshot ran nothing when its directory sat behind a symlink (macOS keeps temp dirs under /private/var, reached as /var): its "am I the entry point" check compared a real path with the typed one. Both sides now go through realpath. Caught by the macOS CI job on 0.4.0.

Install: npm i -g declick@0.4.1 · npm · declick.dev

declick 0.4.0

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31
  • declick setup [--dry-run] [--no-adopt] [--no-rules] [--no-hook] [--no-path] [--keep-adapters]: wires declick into whatever agent is on the machine in one call. Puts ~/.declick/bin on PATH, builds an adapter for every MCP server it finds in .claude.json, .mcp.json, installed Claude Code plugins and Codex's config.toml (a server needing a bearer it does not have is skipped and named, never dropped silently), adds a <!-- declick:start --> / <!-- declick:end --> rules block to CLAUDE.md or AGENTS.md telling the agent to reach for a declick adapter before an MCP call, WebFetch, a browser read or raw curl, and (Claude Code only) installs a PreToolUse hook that nudges the model once per adapter per session. Running it twice is a no-op for the rules block and the hook and rebuilds no adapter already adapted.
  • declick setup --revert: undoes exactly what setup did, from a byte-exact snapshot taken under ~/.declick/setup/<timestamp>/ before the first write. A file untouched since setup is restored byte for byte, or deleted if setup created it; a file edited since keeps the edits and loses only the rules block or the hook entry. The snapshot also carries a standalone revert.mjs: node ~/.declick/setup/<timestamp>/revert.mjs restores files with no dependency on the package, so it still works after npm rm -g declick.
  • declick uninstall [--yes] [--keep-adapters]: runs a revert if one is available, deletes ~/.declick entirely, and prints the npm rm -g declick line. Refuses without --yes, no interactive prompt.
  • declick doctor reports integration: whether setup has run, whether a revert snapshot is available, which clients have the rules block and the hook, and how many discovered MCP servers are adapted. A ~/.claude with no rules block gets a warning pointing at declick setup, not a blocking failure.
  • The Claude Code hook ships in the package (src/hooks/declick-nudge.cjs) and is copied to ~/.declick/hooks/declick-nudge.cjs by setup; it maps an MCP tool call to its declick adapter through ~/.declick/hooks/servers.json and never blocks a tool call.
  • New env: DECLICK_CLIENT_HOME names the directory the agent clients live under (default os.homedir()), so every path setup touches can be redirected. DECLICK_NUDGE_OFF=1 silences the hook. DECLICK_PATH_PROFILE is a test-only override that sends the shell-profile write to a named file instead of the real one.

Install: npm i -g declick@0.4.0 · npm · declick.dev

declick 0.3.2

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31
  • A reader that closes the pipe early (declick add big-spec | head) gets a clean exit instead of an EPIPE stack trace, from both entry points.
  • npm run qa (scripts/qa-real-specs.sh) is the release gate: six public specs compiled from their live URLs, real keyless calls, the auth path, path --install in a fresh login shell, the web page refusal and the Node guard, from the checkout or, with QA_FROM_NPM=1, from the published package. The 0.3.0 release shipped without it and none of those specs compiled.
  • CI jobs time out after ten minutes, so an open handle left by a failed test cannot hang a run.

Install: npm i -g declick@0.3.2 · npm · declick.dev

declick 0.3.1

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31

Pre-launch QA of the published 0.3.0 on Windows and Linux, against Stripe, GitHub, Slack, Twilio, Openverse, api.weather.gov, apis.guru, two GraphQL endpoints, two reference MCP servers and a SQLite file. Every fix below came out of that pass and carries a regression test; 464 tests pass.

  • License: 0.3.1 is the first release under the Elastic License 2.0 (SPDX Elastic-2.0), reproduced in full in LICENSE. The source stays public and readable: use it, change it, redistribute it, ship it inside your own product. You may not offer it to others as a managed service. Release 0.3.0 as published on npm was released under the MIT license and stays under it. Commercial licenses for teams and production support: https://declick.dev.
  • Governance: a mutating verb with no DASHCLAW_API_KEY set no longer writes a warning line to stderr. It runs, and the envelope records governance: {enabled: false, decision: "skipped", reason: "no guard configured"}. Piping a mutating call now produces the envelope and nothing else.
  • Skills: add writes SKILL.md into every agent skills directory that exists on the machine, not only ~/.claude/skills: ~/.codex/skills, ~/.hermes/skills, ~/.openclaw/skills and ~/.agents/skills when the directory is already there, and none are created for an agent that is not installed. DECLICK_SKILLS is a comma-separated override that replaces the list. declick skill <name> --print writes one adapter's SKILL.md text to stdout instead of disk, for an AGENTS.md or a system prompt. skillText is exported for callers that want to render it themselves.
  • describe pages itself instead of failing lint on a large surface: the page stays under the 2000 char ceiling and ends with a footer naming how many verbs are left, the total, and the flags that reach them (--grep, --offset, --limit, --verb). declick lint measures the paged page, so a 60 verb spec compiles.
  • YAML: zero-indent block sequences, plain-scalar folding, anchors before a sequence, sequence-item indent and multi-line quoted scalars all parse. Stripe's spec3.yaml parses to 419 paths, Openverse's to 17.
  • Engine detection: a spec URL whose head does not show the openapi key no longer routes to the web engine, and a spec URL that answers 404 fails naming the status (GET <url> -> 404) instead of reporting no recipes.
  • run: a verb's compiled returns.rowsPath is auto-unwrapped only when --fields or --limit is passed, so an unfiltered call returns the resource as the API sent it; rowsPath is compiled only for a list-shaped property.
  • import reads export's envelope as it comes, so declick export <name> | declick import - round-trips without hand-editing the bundle.
  • doctor: healthy follows blocking only, so a fresh home whose bin directory is not yet on PATH reports healthy with one warning rather than unhealthy.
  • A failed add prints the first eight lint errors followed by a count of the rest, instead of one unreadable line.
  • Node below 24 prints one line naming the version it found and exits 1, from both bin/declick.mjs and bin/run.mjs. The engine index pulls in node:sqlite at import time, so the check now runs before the engines load on either entry point.
  • declick engines lists sqlite once, and reports desktop as not ready with "Windows only (deskclaw UI Automation)" on any platform that is not Windows.
  • Launcher: a launcher declick itself wrote is no longer read as a name collision, so add and build work after declick path --install puts ~/.declick/bin on PATH. The .cmd twin is written on Windows only.
  • saveManifest normalizes a description on the way to disk: collapsed to one line, then its first sentence, and a first sentence still over the bound cut back to the last word boundary (80 chars for a verb, 200 for args and flags). add and build normalize before lint, so a spec with long, multi-line or backticked descriptions compiles: Stripe (594 verbs), GitHub (1224), Openverse and api.weather.gov all add from their public URLs. import still lints the bundle as given, since a bundle is untrusted input.
  • The secret scanner skips example and default values, which are spec-provided text (GitHub's example SHAs are not credentials).
  • YAML: a mapping key that contains a colon (read:pets:, x:y:) is a key, in block and flow context, so OAuth scope maps and a sibling api_key scheme survive; the YAML twin of the petstore spec now compiles the same auth keys as the JSON one.
  • OpenAPI: a spec that declares no servers gets its origin as the base URL, not the spec's directory. A required header parameter that is not a security scheme (User-Agent, Accept) is an ordinary flag with a default, never an auth key. rowsPath is compiled only for a list-shaped property (data, items, results, ... or a small object whose other keys are pagination), in the openapi, mcp and postman engines alike; --fields naming keys of the object itself projects the object instead of unwrapping.
  • A bad --limit (0, abc) returns the failure envelope on stdout from both entry points instead of a bare stderr line.
  • Did-you-mean prefers a prefix match (get-pet suggests get-pet-by-id, descr suggests describe) before edit distance, in the runtime and the management CLI.
  • add on a plain web page URL without the web: prefix says it is not an API spec and shows both the web: form and the spec alternative; engines --source on the same URL suggests the web: form. A failed add caps data.errors at 50 and reports data.errorCount.
  • path --install writes the file the login shell reads: ~/.zprofile for zsh (the macOS default), ~/.bash_profile when it exists for bash on macOS, fish_add_path in config.fish for fish, ~/.profile otherwise. The stderr hint after add names the same file.
  • The mcp and cli engines spawn cmd.exe explicitly instead of passing shell: true, so Node 24 no longer emits a DEP0190 warning into the output.
  • creds: the "or run: creds mint " hint on an exit 4 appears only when that tool is on PATH.
  • sqlite: a query verb called without --sql says so.
  • add app:<w> --recipes runs the launcher and skill preflight before importing recipes, and a fresh adapter directory is rolled back when compile or lint refuses, so a refused add no longer leaves ~/.declick/<name>/recipes/ with no manifest.
  • README, docs, site and package description updated for agent-neutral skill discovery and the optional guard; DashClaw is explained and linked. The reference material (desktop recipe steps, the manifest, environment variables) moved to docs/REFERENCE.md.

Install: npm i -g declick@0.3.1 · npm · declick.dev

declick 0.3.0

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31
  • remove <name> <verb> now resolves the verb before touching disk: exit 2 for an unknown verb, exit 1 for a spec-backed engine (openapi verbs come from the spec, not per-verb files; rebuild with --verbs instead), and --force is required to delete the last desktop recipe (it would otherwise delete the whole adapter silently). The response for the last-verb case carries adapterRemoved: true.
  • --dry-run works on every management command that writes: add, build, accept, import, skill, remove, path --install, desk arm|disarm. It compiles, lints and previews without writing anything, and sets meta.dryRun: true. author, repair and ui have no preview (they drive a live app or a server) and refuse --dry-run with an error, as does add --goal without --recipes.
  • Row projection: --rows <path> unwraps a dotted array inside a response object (meta.rows names the path used, meta.extra carries the sibling fields such as a cursor or total). Without --rows, a verb whose spec says where its rows live (returns.rowsPath) auto-unwraps them when --fields or --limit is passed; describe, manifest and other non-verb payloads are never auto-unwrapped.
  • --fields now takes dotted paths (--fields error.code,items.0.name) resolved per row. A field list that matches nothing on any row is exit 1 naming the available top-level keys; a partial miss is reported in meta.unknownFields instead of failing.
  • openapi verbs carry a compiled verb.returns ({shape: 'array'|'object'|'scalar'|'none', fields, rowsPath?}) read from the first 2xx (or default) JSON response schema, capped at 30 fields with truncated: true. describe --full prints it as a -> line; describe --json includes it on every verb (null when the spec has no response schema). Desktop verbs get a minimal returns: {shape:'text', from:<read alias>} when the recipe declares one.
  • import refuses to silently replace an adapter that already exists under a different source, engine or baseUrl: exit 1 naming what differs (data.diff), unless --force. The whole import is transactional: a mid-import failure rolls back only what that import created, leaving a prior adapter of the same name untouched. add/build preflight the launcher and skill name before writing anything, for the same reason.
  • Manifest validation (declick lint, and every add/build/import) now rejects a source, window, baseUrl, arg name/description, flag name/description, returns.rowsPath/field name, or auth.env entry that spans multiple lines, contains a backtick, starts with #, or exceeds its length bound. This is the rule already applied to verb descriptions, now applied everywhere spec or bundle text reaches an agent.
  • SKILL.md generation is fence-safe: any `` in an embedded description can no longer close the surrounding fenced block. writeSelfSkill no longer overwrites a hand-written `declick` skill in a skill dir; it only writes dirs where that file is absent or already carries the `Generated by declick` marker.
  • Seven new engines, all built in with no new dependency: mcp (stdio and streamable http), web (a real browser over CDP; a miss returns the page's elements, never a screenshot), graphql, postman (postman v2.1 and insomnia v4), har, sqlite (tables and views become list/get/insert/update/delete plus a parameterized query), and cli (compiled from a tool's own --help). Swagger 2.0 and YAML specs compile through the openapi engine. declick engines --source <x> says where a source would land before anything is written; declick add now also takes --host (which captured host is the API) and --url (the endpoint a GraphQL schema file does not carry).
  • New commands: declick commands and declick <cmd> --help (one row: flags, examples, whether it previews) render from the same table that generates the shipped declick skill, so the skill cannot drift from the CLI; declick audit reads the run log newest first; declick desk windows|tree|read|clipboard and declick web tree return the desktop and a web page as data; declick import --example and declick manifest --schema print a valid bundle and the manifest field reference; declick describe gained --grep and --offset; declick doctor separates blocking from warnings and probes each engine's tools.
  • Request flags on the HTTP engines: --header, --base-url, --server, --content-type, --body-file, --output, --retry, --timeout, --verbose and --curl, listed by describe --full. --retry and --timeout now require a value instead of silently falling back to the default.
  • An api key that lives in the query string is masked in --curl and --verbose on live calls, the same as a header one; only the fetch itself sees the real value. --curl on a live multipart request now carries the body and its boundary content type instead of dropping both.
  • The cli engine quotes every argument it hands to a .cmd or .bat tool, not only the ones containing a space: a value with &, |, >, < or ^ used to reach cmd.exe as a second command. Same fix for the mcp client's npx/npm shell path.
  • sqlite: --limit is the output contract's flag, so meta.count is the true row count and meta.truncated says when there is more; a column named like a contract flag (limit, fields, output) is renamed param-<name> and still reads and writes its own column, instead of making the whole table unaddressable.
  • A desktop recipe's read step re-resolves against a fresh tree before reading a property, so a read after a set, type or click reports what the action did instead of the value captured at find time.
  • meta.credentials now records scopedTo and sentTo when a key is released across origins (--base-url or DECLICK_ENV_ALLOW); the refusal on the blocked path no longer names the flag that would skip it.
  • Desktop recipes get a much larger step vocabulary: read-all (every match of a path as rows), wait-for/wait-for-text (poll for an element or text up to a timeout), assert (compare a live value with equals/matches), clipboard get|set, dismiss (Escape), launch (start the app inline, or from manifest.launch when the window is not open), scroll, expand, collapse, select, context (right-click), set (drive a toggle to a state), and optional: true on any step to skip instead of fail when its element is not there. declick desk windows|tree|read|clipboard exposes the same underlying reads as CLI commands.
  • Governance: once DASHCLAW_API_KEY is set, strict is now the default: an unreachable, timed-out, or non-decision guard response is exit 3, not a warn-and-proceed (DECLICK_GUARD=open restores the old fail-open behavior). DASHCLAW_URL has no default endpoint and is required alongside the key. Every envelope carries meta.governance:{enabled,decision,reason}, and every invocation appends a redacted line to ~/.declick/audit.jsonl (DECLICK_AUDIT=off to disable; declick audit reads it). declick ui now requires a per-start X-Declick-Token on every mutating POST.
  • deskclaw companion: declick 0.3 needs deskclaw 0.3.0 or newer for the attributed snapshot lines (value=, toggle=, selected=, expanded=, offscreen=) the new read/assert steps depend on.

Install: npm i -g declick@0.3.0 · npm · declick.dev

declick 0.2.0

Choose a tag to compare

@ucsandman ucsandman released this 04 Sep 14:31

Everything an agent needs is now a declick command with the same JSON envelope and exit codes as the generated adapters.

  • New commands: run, status, doctor, auth, manifest, proposals, accept, recipes, recipe, skill, export, import, engines, version, path [--install], desk status|arm|disarm, remove <name> <verb>. help exits 0. add --verbs a,b, --tag t, --engine e, --force; --recipes accepts a file or -.
  • Every management command honors --json (default when piped), --fields, --limit; errors are {ok:false,error,exit} envelopes. list survives a corrupt manifest. ui prints {url,port} on stdout and has an add form.
  • Flags: --k=v, --no-flag, boolean flags never consume the next argument, repeated flags become arrays, -- ends flags, bad --limit is exit 1, unknown flags on a verb are exit 1. Hyphenated query and body names work.
  • OpenAPI: relative server URLs resolve against the spec URL, server variables substitute, local $ref parameters and bodies resolve, path plus operation parameters dedupe, required query flags are enforced and shown, oauth2 / openIdConnect / cookie auth is sent, 204 and empty bodies succeed, form bodies use the right content type, missing operationIds no longer collide, reserved names are renamed param-*, file sources are stored absolute.
  • Desktop: findByPath backtracks; a closed window is reported as such; last-error.json clears on success and after repair; undeclared {{vars}} are exit 1; stored recipes are validated; missing deskclaw is a clear message.
  • Authoring: the live replay goes through the governance guard; proposals are kept on every rejection including an unarmed desk; any ``` fence parses; timeouts are reported as timeouts; the child env is an allowlist; screen text is fenced as untrusted in the repair prompt; mutating defaults to true.
  • Governance: shared src/guard.mjs with a 3s timeout, r.ok and decision checks, warn surfaced, method-based risk scores, DECLICK_GUARD=strict. A block is a JSON envelope with exit 3.
  • Security: ui refuses foreign Host and Origin and non-JSON POSTs; adapter and verb names are validated on every path (no ../); SKILL.md frontmatter is quoted and sanitized and never overwrites a foreign skill; launchers refuse to shadow an existing executable; the secret scanner catches mid-string tokens and stops rejecting long kebab names; manifests are written atomically with manifestVersion.
  • remove deletes the launcher and the skill too. describe shows base URL or window and --full. SKILL.md gets runnable examples, the declick run fallback and engine-specific exit code advice. declick ships its own SKILL.md.
  • mcp and web stubs exit 1 (was 4, the auth code). YAML specs get a convert hint instead of a JSON parser error.

Install: npm i -g declick@0.2.0 · npm · declick.dev