qory

command module
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

🐝 qory

A harness is what your coding agent reads before it works: instructions, skills, agents, commands and settings. qory builds the harness of a repository from modules. Each module is one piece of harness: the piece every repository of your team shares, the piece for apps built on your framework, the piece this repository alone needs. The repository commits the list of modules, not a copy of their files.

The problem

Your coding agent reads its harness from the repository. You have many repositories, and more than one agent. Claude Code reads .claude, Codex reads .codex, Gemini CLI reads .gemini. So every repository contains one copy per tool. When the shared part improves, the copies drift, and nothing shows which version a checkout runs with.

Don't worry, use Qory

What qory does

A stack lists modules in order: the harness your team shares, the harness for apps built on the framework, the harness this repository alone needs. qory composes them into one tree and writes that tree the way each tool reads it. The tree is linked into the checkout and kept out of git. A report lists the module every entry came from.

A module is written once and serves Claude Code, Codex CLI, Gemini CLI, OpenCode, Cursor, GitHub Copilot CLI, Amp, Goose, and every tool that reads AGENTS.md and .agents/skills. A checkout can serve two tools at once, and both read the same harness.

The model is Docker's: a module is an image, the stack is the Compose file, and the composed tree is what runs. One rule differs on purpose. When two modules provide the same entry, qory refuses to compose until the stack selects which one to keep. Nothing wins by coming last.

Three steps

  1. Write qory.yaml in the repository, or let qory setup repo write it:

    apiVersion: qory.dev/v1alpha1
    harness:
      target:
        runtime: claude          # or both at once: [claude, codex]
        model: opus
      modules:
        - name: core             # what every repository of yours gets, pinned to a tag
          source: {git: https://github.com/acme/harness, ref: v2.4.0, path: core}
        - name: nextjs           # the harness for Next.js apps
          source: {path: ../harness/nextjs}
        - name: app              # this repository's own, committed with it
          source: {path: ./harness}
    

    Every module has a qory-module.yaml that defines its name. A repository can also take a stack someone else delivers, a qory-stack.yaml: it selects that stack under extends, defines what it composes it for under target, and adds its own modules. The delivered modules cannot be changed. A runner that has the stack tree selects the base with qory harness compose -f <stack> instead, and the repository's file then contains no version, ref or URL of it. The harness repository states the qory it needs once, in its own qory.yaml, qory: ">=0.5.0", and that requirement applies to every stack it delivers.

    apiVersion: qory.dev/v1alpha1
    harness:
      extends: {git: https://github.com/acme/harness, ref: v2.4.0, stack: nextjs}
      target: {runtime: claude, model: opus}
      modules:
        - name: marketing          # the harness repository exports it too
          source: {git: https://github.com/acme/harness, ref: v2.4.0, module: marketing}
        - name: app
          source: {path: ./harness}
    

    stack and module select what the harness repository publishes in the exports section of its own qory.yaml, so nobody outside it depends on its directories:

    exports:
      dir: ./harness               # where stacks/ and modules/ are; default: the root
      stacks: [nextjs]
      modules: [core, nextjs, marketing]
    
  2. Compose it:

    qory harness compose
    
  3. Start your agent in the checkout. It reads the composed tree through the files it already looks for.

Install

With Homebrew:

brew install qoryai/tap/qory

With the install script, which puts the release binary in ~/.local/bin:

curl -fsSL https://raw.githubusercontent.com/qoryai/qory/main/install.sh | sh

From source, with Go 1.27 or above:

go install github.com/qoryai/qory@latest

To update, run qory update: it installs the newest release the way this qory was installed, with brew, with go install, or by replacing the release binary in place after checking it against the release's checksums. Every command looks for a newer release when it runs on a terminal, requesting the latest release from GitHub at most once an hour, and prints a notice after its output when the newest release is ahead of its version. A build from main between releases prints the notice only when it is behind a release. Set QORY_NO_UPDATE_CHECK=1 to turn that off; it is off when CI is set.

Try it

mkdir hello && cd hello
qory setup example       # writes a stack and two modules
qory harness compose     # or: qory hc; for Codex: qory hc --runtime codex
claude                   # type /hello
qory harness remove      # or: qory hr

Both modules ship a greet skill. The README that qory setup example writes lists the line to delete to watch qory refuse the collision. For a real repository, run qory setup repo instead.

The same example, observed, then behind a wall

qory run starts the agent on the composed harness inside the session runner: every connection it makes goes through a proxy on your machine, and the session is recorded.

qory run -- -p "/hello"         # one headless turn, observed
cat .qory/runs/*/events.jsonl   # what it reached, what it printed, how it ended

Without a wall the proxy sees only programs that honour it. A wall starts the agent in a container whose one route out is that proxy. It needs the docker command and an image of yours that contains the agent; qory builds none. A minimal one for Claude Code:

FROM node:22-slim
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates \
 && rm -rf /var/lib/apt/lists/* && npm install -g @anthropic-ai/claude-code
# The container runs as your user, who has no home in the image.
ENV HOME=/tmp
docker build -t hello-agent:1 .
export CLAUDE_CODE_OAUTH_TOKEN=...       # from `claude setup-token`; or ANTHROPIC_API_KEY
qory run --wall docker --image hello-agent:1 --env CLAUDE_CODE_OAUTH_TOKEN -- -p "/hello"

On a Mac, set wall.helper to the Linux build of the same qory release first; see Running a session. That run passes the token to the container. The last step keeps it outside: define in ~/.config/qory/runner.yaml what this machine has and what the agent may reach,

apiVersion: qory.dev/v1alpha1
egress:
  mode: enforce
  allow: [api.anthropic.com]
credentials:
  model:
    env: CLAUDE_CODE_OAUTH_TOKEN
    hosts: [api.anthropic.com]
    auth: {scheme: bearer}
    placeholders: [CLAUDE_CODE_OAUTH_TOKEN]
wall:
  adapter: docker
  image: hello-agent:1

and pass the run a policy that selects the credential, kept outside the checkout:

# ~/hello-policy.yaml
version: 1
egress:
  mode: enforce
  allow: [api.anthropic.com]
credentials:
  - name: model
qory run --policy ~/hello-policy.yaml -- -p "/hello"

The agent greets you as before. Inside the container CLAUDE_CODE_OAUTH_TOKEN is a placeholder; the proxy sets the real token on each request to api.anthropic.com, which the record lists with the credential's name and never its value, and everything else the agent tries to reach is denied and recorded.

Worktrees

One branch per worktree, beside the main checkout. qory prepares the worktree the way the repository's qory.yaml defines and composes the harness into it:

# qory.yaml, committed, beside the harness section
apiVersion: qory.dev/v1alpha1
worktree:
  base: main                     # the base branch, read on the remote; default: the remote's HEAD
  link: [.env, .env.local]       # linked from the main checkout into the worktree
  run:
    add: [pnpm install]          # run in the new worktree
qory worktree add feature        # ../wt-feature on branch feature, pushing to origin/feature
qory worktree add feature --base v1.2.0   # a branch that exists is moved onto the base, after a question
qory worktree add feature --offline       # without the fetch every add starts with
qory worktree add --branch feature   # attach to the remote's feature: fetched, tracked, refused when the remote lacks it
qory worktree add --pr 7             # attach to pull request 7: its branch, found among the remote's refs
qory worktree add review --pr 7      # the same, in ../wt-review
qory worktree remove             # the worktree you stand in, and its branch
qory setup shell                 # make your shell cd into a new worktree, and back on remove

Every add fetches the remote first, so a new branch starts at the remote's tip and a branch pushed from another machine is tracked instead of cut anew; a fetch that fails stops the add, and --offline goes on with the refs already there. The branch goes with the worktree on remove: quietly when every commit of it is on the remote, in the main checkout or on the base it was cut from, and after a question otherwise, with push, keep, delete anyway and stop as the answers. --keep-branch keeps it, and worktree.branch: keep makes that the default. -v on either verb prints each git command as it runs, and what the configured commands print.

--pr sends no request to a hosting API: the pull request's head is one of the refs the remote publishes, refs/pull/<n>/head on GitHub and Forgejo, refs/merge-requests/<n>/head on GitLab, refs/pull-requests/<n>/from on Bitbucket Server. worktree.pr: refs/.../{n}/... in the repository's qory.yaml defines the layout of another host; a host that publishes none, Bitbucket Cloud, takes --branch with the pull request's branch.

Where a worktree goes and what it is called is your choice, not the repository's: worktree.dir, worktree.name and worktree.branch in your own qory.yaml, which qory setup machine writes. A file whose path the repository's qory.yaml must not mention goes there too:

# ~/.config/qory/qory.yaml
worktree:
  link: [{from: ~/secrets/app.env, to: .env}]   # this machine's path, linked as .env

Commands

qory setup repo          # write the repository's qory.yaml: its stack, module and worktree settings
qory setup example       # write the hello example into the current directory
qory setup machine       # write your qory.yaml in ~/.config/qory: how qory runs here
qory setup shell         # completions, and a shell that follows worktree add and remove
qory harness compose     # compose the stack into the checkout you stand in   (qory hc)
qory harness inspect     # the report: every entry and the module it came from (qory hi)
qory harness remove      # remove the composed tree and its links               (qory hr)
qory harness launch      # the command that starts a runtime on the tree          (qory hl)
qory run                 # start a runtime on the tree, observed and recorded
qory worktree add        # add a worktree for a branch and prepare it            (qory wa)
qory worktree remove     # remove a worktree and its branch                      (qory wr)
qory worktree list       # every worktree with its branch                        (qory wl)
qory config              # every setting, its value and the file it came from
qory update              # install the newest release; --check only reports whether one exists

Flags worth knowing on compose:

-f <stack>             compose this stack; as the base of the repository's document when that extends one
--dry-run              print the report and write nothing
--runtime claude,codex render for these runtimes instead of the document's
--model opus           write this model instead of the document's
--force                replace a tracked, unmodified file where a link goes
--update               fetch every git source again
--check                exit 6 when the composed tree is behind the stack and modules
--home <dir>           compose under a directory outside the checkout, and write nothing into it
--no-links             keep the checkout untouched; the tree goes under .qory

Two qory.yaml files are read. Every setting has a default, so both are optional. The repository's file is committed and contains what the repository decides: its stack, and what a worktree needs; it may be harness.yaml instead, a file name that does not mention the tool that reads it. Your file, in ~/.config/qory, defines how qory runs on this machine for every repository: the runtime to compose for, where worktrees go, the git timeout. The repository's file is read on top of yours. qory config shows every setting and the file it came from. The reference, one page per command, is under docs/commands.

What you get

  • The files your tool reads, linked to a composed tree under .qory and kept out of git. Your own settings.local.json stays yours.
  • Settings merged from every module, in the tool's own format. Permission lists and hooks join. A value set twice to different things is a collision, never a silent override.
  • MCP servers, one file each in a module, written where every tool reads them.
  • Modules from a directory beside the repository, or from a git repository at a tag, pinned by commit in the report. A repository that publishes stacks and modules lists them under exports, and a consumer selects them by name, never by directory.
  • One instruction file, joined from the modules in order, under the name each tool wants.
  • A report that lists the module of every entry. When two modules provide the same entry, a refusal with the lines that resolve it.
  • Part of a module, when that is all you want. exclude leaves entries, the instruction section, settings fragments or variables out. only takes the listed things, plus what they need as the module's manifest declares it, and nothing else: only: {skills: [deploy]} is the deploy skill, the command it runs and the agent it calls, from a module full of other things. A required entry you take from another module instead is one exclude line beside the only.

The composed tree

The home, .qory/harness, contains one directory per runtime. Most of what is in it is a symlink to a file in a module: every skill, agent, command and hook. Beside the links are the generated copies: AGENTS.md at the root of the home, the instruction file each runtime wants, its settings and its MCP file, each joined from the modules' fragments.

Editing a module's file is live through the link. Editing a module's instruction section or a settings fragment is not: the merged copy is generated, and it stays as it was until the next compose. qory harness compose --check compares the home with what the stack and modules define and exits 6 when a merged copy is behind, which is the check a CI job runs.

What the checkout contains is links too. .claude is a real directory with one symlink per entry, so Claude Code's own settings.local.json stays beside them; .mcp.json and a root AGENTS.md are symlinks. A tool that walks the tree has to follow them:

  • find needs -L.
  • grep -R with a symlink as its operand without a trailing slash reads nothing with BSD grep on macOS and follows the link with GNU grep on Linux, and neither reports an error. Pass it the directory with the slash, grep -R pattern .claude/, or use -R -L.
  • rg needs --follow.

git status does not show the tree. Every path qory writes is listed in .git/info/exclude, which every worktree of a repository shares.

A home outside the checkout

The tree can live outside the checkout, owned by whatever composes it, a workflow or a launcher, and the checkout then contains nothing of it: no link, no .qory, no exclude line, so a tracked harness/ directory is no collision and a pull is an ordinary pull. --home <dir>, or harness.home in your own qory.yaml, defines the directory, and every checkout and worktree gets its own home under it. Each tool takes such a home from its own command line or environment, and qory harness launch prints the command:

qory harness compose --home ~/.cache/qory/homes
eval "$(qory harness launch --runtime claude --home ~/.cache/qory/homes)"

For Claude Code that is --plugin-dir for a plugin the compose renders, --settings for the permissions, hooks, environment and model, --mcp-config for the servers, --append-system-prompt-file for the instructions, and --setting-sources user so no .claude of the checkout or of a directory above it is read. Cursor takes the same plugin, Codex takes the tree as its CODEX_HOME, OpenCode as its OPENCODE_CONFIG_DIR, Copilot the skills and agents through --add-dir, Amp and Gemini their settings file. Every line is the tool's own template, and harness.launch.<runtime> in your qory.yaml changes the command, the arguments or the variables when a tool's flags move. --json prints the same as one object. The contract lists what each tool takes from outside and what it reads from the checkout.

Running a session

qory run starts the runtime on the composed tree inside the session runner of qoryai/runner: the same launch as qory harness launch, with every connection the runtime makes going through a proxy on your machine and recorded, and the session written as events beside its output.

qory run                              # the composed runtime, at your terminal
qory run claude -- -p "Reply pong"    # one headless turn; arguments after -- go to the runtime

The record is .qory/runs/<id>/: events.jsonl, one event per line, and output.log, the session's bytes. One optional file, ~/.config/qory/runner.yaml, defines what the runner does on this machine. It lives beside your qory.yaml and nowhere else, so a repository cannot set it:

# ~/.config/qory/runner.yaml
apiVersion: qory.dev/v1alpha1
egress:                  # what the runtime may reach; enforce denies the rest
  mode: enforce          # or observe: record everything, deny only what deny lists
  allow: [api.anthropic.com, "*.github.com"]
  deny: [gist.github.com]                # denied in either mode, whatever allow lists
server:                  # the server every run reports to; optional
  url: https://qory.example             # a scheme and a host, nothing after
  access_key: ak_f1xt0re000000000       # the key the server issued this machine
  secret: fixture-secret-not-a-real-one # or QORY_SERVER_SECRET in the environment
wall:                    # start the runtime in a container; optional
  adapter: docker
  image: example.com/agent:1            # yours: the runtime and your toolchain
  env: [ANTHROPIC_API_KEY]              # names; nothing else of your environment goes in
  mounts: [/srv/odoo:ro]                # what else of your machine it sees; optional
  memory: 14g                           # and cpus, pids_limit, shm_size; optional
run:                     # optional
  timeout: 5h30m         # stop a runtime that runs this long
  stop_signal: SIGINT    # requests it to stop; the runtime's descriptor's, else SIGTERM
  stop_grace: 30s        # between that signal and SIGKILL; 10s

qory run runs whichever runtime the harness is composed for, and none of the above is particular to one. The runner reads what it needs of a runtime from a descriptor, a file of data in the runner contract's format: how its hooks are installed, what its output means as events, which signal requests it to stop. The runner ships Claude Code's. ~/.config/qory/runtimes/<runtime>.yaml describes another, or replaces the one shipped; and a runtime nothing describes runs all the same, the run, its log and its egress recorded and the session's own events not.

A module declares the hosts it reaches under egress in its manifest, and the compose unions them into the report. The runner reports them as harness_hosts in dev.qory.run.policy_applied, for a receiver to compare with the policy; they decide nothing. The policy alone defines what the runtime reaches.

With a server configured the runner starts by fetching the server's configuration, signed with the access key and the secret, and does not start unless the server answers: the events go where the configuration defines, and when it selects a run configuration, that is the run's policy, fetched for the checkout's forge and repository and reloaded when the server reports it changed. --local runs with the files alone and the machine's policy; the server is not contacted. A denied connection is recorded and the session goes on; only a time limit you set ends a session: --timeout 5h30m, or run.timeout, stops the runtime then, dev.qory.run.exited records the limit as the reason, and qory run exits 124.

A system that starts runs of its own sets their id and labels, and passes each its policy:

qory run --run-id "$uuid" --label run_key=1234 --label issue=77 \
  --policy /etc/factory/shop-policy.yaml --timeout 5h30m --stop-grace 30s -- -p "$prompt"

--run-id is the id the caller already has, a UUID in lower case, and the labels go into dev.qory.run.started and onto the run configuration request, where a server ties the run to its own records and chooses its policy. Two labels come from the checkout's origin remote unless --label sets them: forge, the remote's host, and repository, its path without the leading slash and .git, so git@github.com:acme/shop.git is github.com and acme/shop; a checkout with no remote, or one on this machine, has neither. --policy is one run's own policy, in the runner contract's format, kept outside the checkout, for a machine without a server. It narrows only: under an egress section in mode enforce the run reaches the file's hosts the section covers; with no section, or one in mode observe, the file stands as it is; the deny lists of both apply either way. With a server configured the server's run configuration is the policy and --policy is refused; --local keeps it. The server's secret stays the runner's: QORY_SERVER_SECRET is taken out of the session's environment.

Credentials the agent never has

Behind a wall a run needs no credential inside the container. runner.yaml defines what the machine has, and a run's policy selects among it by name:

# ~/.config/qory/runner.yaml
credentials:
  model:                                  # a token from qory run's environment
    env: CLAUDE_CODE_OAUTH_TOKEN
    hosts: [api.anthropic.com]
    auth: {scheme: bearer}                # or basic with a username, or header with a name
    placeholders: [CLAUDE_CODE_OAUTH_TOKEN]
  product:                                # a token from an adapter of yours
    adapter: [/opt/adapters/code-host, --repo, "${argument}"]
    argument: '[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+'
# the run's policy, passed with --policy
version: 1
egress:
  mode: enforce
  allow: [api.anthropic.com, git.example.com, api.git.example.com]
credentials:
  - name: model
  - {name: product, argument: acme/shop}

The runner keeps each token outside the container, and its proxy sets it on the requests to the hosts it is for. The container gets a placeholder where a program wants a credential set, and never the token. An adapter is a program of yours written for one kind of host, such as a source code host: it runs outside the container and prints the token, its expiry, and the hosts, the scheme and the paths the token is for, so qory defines no host of its own. Its paths are where the token goes on those hosts, and under enforce the run's whole reach there: the runner refuses every other path on them, another organization's repository included. Under observe the runner sends such a request on without the token and records it. egress.paths in a policy limits a host to paths as well, with or without a credential: on a host with both, a path passes under enforce when it matches both lists, and under observe the runner sends the rest on and records it, with the token where the adapter's paths match. On these hosts a path that could be read two ways, such as one with an encoded slash, is refused in either mode. The runner's contract has the adapter's document and the rules.

An integration is an adapter published apart that describes itself: Qory's own qory-<name>, such as qory-github from qoryai/integrations, or a program of yours under a name of your own. Declare it and qory writes the definition:

# ~/.config/qory/runner.yaml
integrations:
  github:                                 # qory-github, found on the PATH
    settings:
      app_id: 123456
      private_key_file: /etc/qory/github-app.pem
      permissions: {contents: write, pull_requests: write}
  tracker:                                # a program of yours, by its path
    program: /opt/acme/bin/acme-tracker
    settings: {url: https://tracker.acme.example}

Before a run qory runs <program> describe. The program prints its description, the settings it takes as a JSON Schema and the roles it plays, and qory checks the settings against it. The credential role defines the credential whose name is the key, as if the file contained

credentials:
  github:
    adapter: [/usr/local/bin/qory-github, credential, --settings, '{"app_id":123456,"private_key_file":"/etc/qory/github-app.pem","permissions":{"contents":"write","pull_requests":"write"}}', --, "${argument}"]
    argument: '[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9_.-]{1,100}(,[A-Za-z0-9][A-Za-z0-9-]{0,38}/[A-Za-z0-9_.-]{1,100})*'
    hosts: [github.com, api.github.com]

and a policy selects it by the key, {name: github, argument: acme/shop}. program sets the program's absolute path or its name on the PATH; without it the program is qory-<key> on the PATH. On a machine whose PATH is not its owner's alone, set program to each program's absolute path. qory runs a program the run cannot write: one outside the checkout and outside every mount the wall makes read-write in the container, wall.mounts and --mount without :ro, judged by where its links lead: a link on a PATH entry the checkout controls that resolves outside the checkout is judged by where it resolves. The rule applies to each run as it starts, so a program written into a directory while that directory was mounted read-write is judged by where it is on every run that follows; keep a program's directory out of the read-write mounts. The resolved file, every directory above it up to /, and every directory above each link on the way, the PATH directory among them, keep one rule: root or the user running qory owns each, and each link on the way; other users may write none; and a group may write one when the group is root's, gid 0, wheel or admin, or the owner's primary group when that group has the owner's name. A directory root owns with the sticky bit set, /tmp or /nix/store, keeps the rule. A default Homebrew install and a ~/go/bin of a user's private group keep it. qory run prints the program it found on a line of its own. The settings go on the adapter's command line, which other processes of the machine can read, so a secret is refused there: the description marks it, a property of the settings themselves, and the settings define the path of the file that contains it, private_key_file and never private_key. The settings are compact JSON with the keys in the file's order, <, >, &, U+2028 and U+2029 escaped, and every $ in them written \u0024, as the integration contract defines for a declaration, so the adapter's ${argument} is the policy's argument alone. A name the credentials section defines itself is the section's: qory run and qory config print this on a line of their own, qory config describes the integration and lists it as shadowed, and a run leaves it undescribed. A run whose policy is on this machine describes the integrations its credentials select; a run whose policy the server supplies describes every one. A program that does not answer within 10 seconds, a description the integration contract refuses, settings the description refuses, and an integration that plays no role qory expands stop the run before it starts. qory config describes every integration and lists what each defines.

For those hosts, and no other, the proxy ends the container's TLS itself, with an authority made for the run whose key never leaves the runner. The container receives one bundle to trust, its image's own authorities and the run's certificate, through SSL_CERT_FILE, GIT_SSL_CAINFO, NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE and AWS_CA_BUNDLE, or the variables wall.ca_env lists. The record lists the terminated hosts and, for each request to one, the method, the path and the credential's name.

A job ends with qory run resend <run-id>, whatever happened before it. It sends the server what it has not accepted of the run's record, and nothing twice. After a runner that died it first closes the record, dev.qory.run.exited with reason: runner_lost, and removes the containers and networks the run's wall left. It refuses a run that is running, and exits 1 when the server has not accepted everything after --wait, two minutes unless set. The formats are in the runner's contract.

The proxy sees only programs that honour it. A wall makes the rest fail: with a wall section, or --wall docker --image <image> for one run, the runtime starts in a container on a network with no route out, and reaches the proxy, and nothing else, through a relay. The container sees the checkout and the composed home and nothing else of your machine; the runner, the policy, the record and the server's secret stay outside. It needs the docker command and an engine behind it, and an image of yours that contains the runtime; qory builds none. What to know:

  • The model credential goes in by name, wall.env or --env, and is then the agent's. A subscription login kept in a Mac's Keychain does not reach a container; use an API key, or a token from claude setup-token.
  • Inside the container the relay and the hook forwarder are qory's own Linux build. On Linux that is the binary you run. On a Mac, download the Linux archive of the same release for your engine's architecture and set wall.helper to the binary.
  • The container sees the checkout it was started in and no other directory, unless --mount <path>[:ro] or wall.mounts shows it one, at its own path, such as a sibling checkout the session reads. A socket is never mounted. In a git worktree the repository's data lives in the main checkout, outside it, so git inside the container works there only with that directory mounted; a clone works as it is.
  • --cpus, --memory, --pids-limit and --shm-size, or the keys of those names under wall, limit what the container uses. A headless browser wants --shm-size 2g: an engine's default /dev/shm is 64 MB.
  • Behind a wall the proxy reaches your own machine only for a host egress.allow lists itself, in either mode, and never the cloud metadata address. For a local model endpoint or MCP server, list your machine's host name, and point the harness at that name: localhost inside the container is the container.
  • With the engine in a virtual machine, as on a Mac, the runtime's hooks do not reach the runner, so a walled run there has no hook events; the log, the egress record and the structured output are there. On a Linux host they cross.

The format

The stack, the module manifest, qory.yaml, the composition rules and the runtimes are specified in contracts/harness/v1, with JSON schemas and the fixtures the test suite runs.

Contributing

See CONTRIBUTING.md. Contributions are made under the agreement in CLA.md.

Licence

Apache License 2.0. See LICENSE. Qory™ is a trademark of 8wonders GmbH; TRADEMARKS.md defines what you may do with the name.

Documentation

Overview

Command qory composes the harness a runtime loads from modules.

Directories

Path Synopsis
Package cmd is the command tree of the qory binary: one command per noun, one subcommand per verb.
Package cmd is the command tree of the qory binary: one command per noun, one subcommand per verb.
internal
checkout
Package checkout locates the git checkout a command works on and identifies it.
Package checkout locates the git checkout a command works on and identifies it.
compose
Package compose turns a stack into one flat tree: every entry once, from one module.
Package compose turns a stack into one flat tree: every entry once, from one module.
config
Package config reads qory.yaml: the repository's own document and the machine's.
Package config reads qory.yaml: the repository's own document and the machine's.
exports
Package exports reads the exports section of a repository's qory.yaml: the stacks and the modules the repository publishes for other repositories, each by name, and the directories they live in.
Package exports reads the exports section of a repository's qory.yaml: the stacks and the modules the repository publishes for other repositories, each by name, and the directories they live in.
gendocs command
Command gendocs writes the command reference, one Markdown page per command, into the directory passed as its argument.
Command gendocs writes the command reference, one Markdown page per command, into the directory passed as its argument.
integration
Package integration runs the program of an integration as the integration contract has it, contracts/integration/v1 of github.com/qoryai/integrations: <program> describe prints the integration's description, one JSON document, and every role is started as <program> <role> --settings <json> -- [the role's own arguments].
Package integration runs the program of an integration as the integration contract has it, contracts/integration/v1 of github.com/qoryai/integrations: <program> describe prints the integration's description, one JSON document, and every role is started as <program> <role> --settings <json> -- [the role's own arguments].
module
Package module reads one directory of harness material: its optional manifest, the entries it ships per kind, its settings fragments and its instruction file.
Package module reads one directory of harness material: its optional manifest, the entries it ships per kind, its settings fragments and its instruction file.
render
Package render writes a composed harness into a checkout the way one runtime reads it.
Package render writes a composed harness into a checkout the way one runtime reads it.
render/amp
Package amp renders for Amp, which reads a project's .amp directory for its settings, AGENTS.md at the checkout root, and skills from .agents/skills.
Package amp renders for Amp, which reads a project's .amp directory for its settings, AGENTS.md at the checkout root, and skills from .agents/skills.
render/any
Package any renders for a program that follows the AGENTS.md convention and has no package of its own, reading the instructions from AGENTS.md at the checkout root and skills from .agents/skills.
Package any renders for a program that follows the AGENTS.md convention and has no package of its own, reading the instructions from AGENTS.md at the checkout root and skills from .agents/skills.
render/claude
Package claude renders for Claude Code, which reads a project's .claude directory: the skills, agents, commands, output styles and hooks under it, its settings.json, and CLAUDE.md beside them, and .mcp.json at the checkout root for the MCP servers.
Package claude renders for Claude Code, which reads a project's .claude directory: the skills, agents, commands, output styles and hooks under it, its settings.json, and CLAUDE.md beside them, and .mcp.json at the checkout root for the MCP servers.
render/codex
Package codex renders for Codex CLI, which reads a project's .codex directory, skills from .agents/skills, and AGENTS.override.md ahead of AGENTS.md.
Package codex renders for Codex CLI, which reads a project's .codex directory, skills from .agents/skills, and AGENTS.override.md ahead of AGENTS.md.
render/copilot
Package copilot renders for GitHub Copilot CLI, which reads agents from .github/agents, hook files from .github/hooks, AGENTS.md at the checkout root, and skills from .agents/skills.
Package copilot renders for GitHub Copilot CLI, which reads agents from .github/agents, hook files from .github/hooks, AGENTS.md at the checkout root, and skills from .agents/skills.
render/cursor
Package cursor renders for Cursor and the Cursor CLI, which read a project's .cursor directory for agents, hooks and settings files such as hooks.json, cli.json and mcp.json, AGENTS.md at the checkout root, and skills from .agents/skills.
Package cursor renders for Cursor and the Cursor CLI, which read a project's .cursor directory for agents, hooks and settings files such as hooks.json, cli.json and mcp.json, AGENTS.md at the checkout root, and skills from .agents/skills.
render/gemini
Package gemini renders for Gemini CLI, which reads a project's .gemini directory, containing its settings.json and the skills, agents, commands and hooks under it, and GEMINI.md at the checkout root.
Package gemini renders for Gemini CLI, which reads a project's .gemini directory, containing its settings.json and the skills, agents, commands and hooks under it, and GEMINI.md at the checkout root.
render/goose
Package goose renders for Goose, which reads AGENTS.md at the checkout root, skills from .agents/skills and agents from .agents/agents.
Package goose renders for Goose, which reads AGENTS.md at the checkout root, skills from .agents/skills and agents from .agents/agents.
render/opencode
Package opencode renders for OpenCode, which reads a project's .opencode directory for agents, commands and hooks, opencode.json for its config, AGENTS.md at the checkout root, and skills from .agents/skills.
Package opencode renders for OpenCode, which reads a project's .opencode directory for agents, commands and hooks, opencode.json for its config, AGENTS.md at the checkout root, and skills from .agents/skills.
report
Package report is the JSON record of one compose: every module with its pin, every entry with its module.
Package report is the JSON record of one compose: every module with its pin, every entry with its module.
source
Package source resolves a module's source to a directory on disk and a pin.
Package source resolves a module's source to a directory on disk and a pin.
stack
Package stack reads qory-stack.yaml.
Package stack reads qory-stack.yaml.
ui
Package ui prints everything a person reads on the terminal, in one vocabulary.
Package ui prints everything a person reads on the terminal, in one vocabulary.
update
Package update finds the newest release of qory and installs it.
Package update finds the newest release of qory and installs it.
user
Package user reads the name to greet a person with from the local configuration.
Package user reads the name to greet a person with from the local configuration.
worktree
Package worktree adds, removes and lists the linked worktrees of a repository, and prepares a new one the way the repository's qory.yaml defines: files linked or copied from the main checkout, or from anywhere on the machine, and commands run in the new worktree.
Package worktree adds, removes and lists the linked worktrees of a repository, and prepares a new one the way the repository's qory.yaml defines: files linked or copied from the main checkout, or from anywhere on the machine, and commands run in the new worktree.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL