SLOPSHOPPER

prompt-mw

Probe: marks prompt.compose and prompt.section output with sentinels

newprompt
A shopper browsing a rack in a slop shop
README

nix-agentic-tools

Stacked commit workflows, MCP servers, and declarative configuration for AI coding CLIs (Claude Code, Codex, Copilot, Kiro). Works without Nix; Nix unlocks overlays, home-manager modules, and devenv modules.

Quick Start

Prerequisites: git-branchless, git-absorb, git-revise.

# Claude Code
cp -r packages/stacked-workflows/skills/stack-* .claude/skills/

# OpenAI Codex
cp -r packages/stacked-workflows/skills/stack-* .agents/skills/

# GitHub Copilot
cp -r packages/stacked-workflows/skills/stack-* .github/skills/

# Kiro
cp -r packages/stacked-workflows/skills/stack-* .kiro/skills/

Each skill is self-contained with a SKILL.md and bundled reference docs.

# flake.nix
inputs.nix-agentic-tools = {
  url = "github:higherorderfunctor/nix-agentic-tools";
};

# Optional: `pkgs.ai.*` for your own use. The modules install this flake's
# builds without it.
nixpkgs.overlays = [inputs.nix-agentic-tools.overlays.default];

# Unfree: claude-code, copilot-cli, kimchi-docs, kiro-cli and kiro-cli-workflows.
# Allow them in the nixpkgs.config your pkgs comes from (NixOS's when
# useGlobalPkgs is set).

# Home-manager config
imports = [inputs.nix-agentic-tools.homeManagerModules.default];

ai = {
  claude.enable = true;
  codex = {
    enable = true;
    settings.model = "gpt-5.6-sol";
  };
  copilot.enable = true;
  kiro.enable = true;
  programs.delegate-routing.enable = true;
  programs.stacked-workflows.enable = true;
  settings.reasoningEffort = "high";
};

# Git companion: mkDefault values on the git.* options, which Home Manager
# applies user-global and devenv at repository scope.
stacked-workflows.gitPreset = "full";

services.mcp-servers.servers.github-mcp = {
  enable = true;
  settings.credentials.file = "/run/secrets/github-token";
};

Static runtime files: every runtime exposes ai.<runtime>.files."<relative-path>" = { text = "…"; };. An entry can instead set source = ./file. Generated context/rule outputs use the same final map at default priority, so an ordinary whole entry replaces them and null suppresses them. Paths are relative to HOME here and to the project under devenv.

# devenv.yaml
# Unfree: claude-code, copilot-cli, kimchi-docs, kiro-cli and kiro-cli-workflows.
# Opt in as for nixpkgs.
allowUnfree: true
inputs:
  nix-agentic-tools:
    url: github:higherorderfunctor/nix-agentic-tools
# devenv.nix
{inputs, ...}: {
  imports = [inputs.nix-agentic-tools.devenvModules.nix-agentic-tools];

  # Optional: the modules install this flake's builds without it. Apply it
  # to use or override `pkgs.ai.*` yourself; the modules then install your
  # `pkgs.ai.*`. `package = null` configures a runtime without installing one.
  overlays = [inputs.nix-agentic-tools.overlays.default];

  ai = {
    claude.enable = true;
    codex.enable = true;

    mcpServers.github-mcp = {
      type = "stdio";
      command = "github-mcp-server";
      args = ["--stdio"];
    };
  };
}

Binary cache

CI builds every package here with this flake's own nixpkgs and pushes the results to nix-agentic-tools.cachix.org. The overlay and the module package defaults hand you those same builds, so they come from the cache whatever nixpkgs you use.

Add the cache to your own Nix configuration. This flake's nixConfig lists it, but Nix ignores a flake's substituters unless you are a trusted user.

# NixOS (or nix-darwin)
nix.settings = {
  extra-substituters = ["https://nix-agentic-tools.cachix.org"];
  extra-trusted-public-keys = ["nix-agentic-tools.cachix.org-1:0jFprh5fkDez9mk6prYisYxzalr0hn78kyywGPXvOn0="];
};
# nix.conf
extra-substituters = https://nix-agentic-tools.cachix.org
extra-trusted-public-keys = nix-agentic-tools.cachix.org-1:0jFprh5fkDez9mk6prYisYxzalr0hn78kyywGPXvOn0=

The packages bring this flake's runtime base (glibc, bash, and so on, about 100 MB) next to your own, from cache.nixos.org, shared by every package here. Module defaults also evaluate a second nixpkgs, like any flake whose modules default to its own packages.

Package sets, unfree, and opting out

  • One nixpkgs builds everything. This flake's nixpkgs input builds the overlay, the module defaults, packages and legacyPackages. Your own overlays on shared dependencies do not reach these packages, and security fixes arrive when this flake bumps nixpkgs (the update sweep runs four times a day). Go and Rust compilers come from this flake's locked toolchain inputs.
  • Unfree is your opt-in, decided by your own nixpkgs. Each package's own license and platform are checked by your nixpkgs with your config (allowUnfree, allowUnfreePredicate, ...), with nixpkgs' own error when it refuses, and meta.available reports that verdict. The package set itself, dependencies included, is built once with this flake's nixpkgs. The check never changes a store path, so it costs no cache hits, and there is nothing to keep in sync. Set them where you set them for nixpkgs (nixpkgs.config, or devenv.yaml allowUnfree). A checkMeta = true config on a nixpkgs older than this flake's may reject newer meta keys; checkMeta is a nixpkgs-CI setting, default false.
  • packages.<system> is free packages only. legacyPackages.<system> has every package plus the nested ai tree. nix run on an unfree package resolves there and needs your opt-in, as in nixpkgs: NIXPKGS_ALLOW_UNFREE=1 nix run --impure github:higherorderfunctor/nix-agentic-tools#claude-code.
  • Swap a dependency with .override. Overriding a package's bun, pnpm, Go or Rust works and costs a rebuild of that package.
  • follows is the opt-out. Setting inputs.nix-agentic-tools.inputs.nixpkgs.follows = "nixpkgs" rebuilds every package on your nixpkgs, with no cache. You then own breakage where a recipe borrows nixpkgs' recipe text, patches or fetchers: tsgolint's patch list, kiro-cli's install step, the pnpm fetcher versions, Go vendorHash.
  • Other systems build locally. On systems this flake does not build (anything but aarch64-darwin and x86_64-linux), cross builds, and musl or static package sets, the overlay builds on your package set.

Skills

Delegate routing for models and effort, plus stacked commit workflows using git-branchless, git-absorb, and git-revise.

<!-- prettier-ignore -->

SkillDescription
/delegate-routingSize model and effort before calling subagents or building workflows
/kimchi-docsSearch the pinned Kimchi docs snapshot and independently pinned workflows source, docs and examples; enable via ai.programs.kimchi-docs.enable
/peer-communicationWrite replies a person reads: answer first, plain words, easy to scan
/stack-fixAbsorb fixes into correct stack commits
/stack-planPlan and build a commit stack from description or existing commits
/stack-splitSplit a large commit into reviewable atomic commits
/stack-submitSync, validate, push stack, and create stacked PRs
/stack-summaryAnalyze stack quality, flag violations, produce planner-ready summary
/stack-testRun tests or formatters across commits in a stack

Packages

<!-- prettier-ignore -->

ServerDescriptionCredentials
aihubmix-mcpAIHubMix image and video generationRequired
context7-mcpLibrary documentation lookupNone
effect-mcpEffect-TS documentationNone
git-intel-mcpGit repository analyticsNone
github-mcpGitHub platform integrationRequired
gitlab-mcpGitLab platform integrationRequired
kagi-mcpKagi search and summarizationRequired
mcp-language-serverLSP-to-MCP bridgeNone
mcp-proxystdio-to-HTTP bridge proxyNone
nixos-mcpNixOS and Nix documentationNone
semble-mcpLocal semantic and lexical code searchNone
nix build .#github-mcp

<!-- prettier-ignore -->

PackageDescription
agnixLinter, LSP, and MCP for AI config files
git-absorbAutomatic fixup commit routing
git-branchlessAnonymous branching, in-memory rebases
git-reviseIn-memory commit rewriting
nix build .#git-absorb

The same git.* options exist on Home Manager and devenv. Each tool's settings are typed from a census of its source and mirror the git key; enable installs the tool:

git = {
  absorb = {
    enable = true;
    settings.maxStack = 50; # absorb.maxStack
  };
  branchless = {
    enable = true; # devenv also runs `git branchless init` on entry
    scopedSync = true; # bare `git sync` moves the current stack only
    settings.test.strategy = "worktree"; # branchless.test.strategy
  };
  settings.merge.conflictStyle = "zdiff3"; # any other git key
};

Home Manager delivers them through programs.git.settings (git.settings is an alias of it). devenv writes a repository-local include kept after every other repository setting, so its values win key by key over user-global ones and hand edits, while keys it does not set fall through.

Agent-adjacent development utilities exposed as pkgs.ai.devTools.*.

<!-- prettier-ignore -->

PackageDescription
beadsGraph-based issue tracker for AI coding agents
ghGitHub CLI
glabGitLab CLI
markdownlint-cli2Configuration-based markdown linter (markdownlint)
microvmThe microvm.nix CLI for managing declared MicroVMs
oxlintFast JS/TS linter with type-aware (tsgo) linting and JS plugins
rumdlFast Rust markdown linter (markdownlint-compatible rules)
tsgolintType-aware linting backend for oxlint (typescript-go)
nix build .#oxlint

Temporarily unclassified supporting packages live in the split-ready packages/<owner>/packages/ai/generic/ trees and are exposed as pkgs.ai.generic.*.

<!-- prettier-ignore -->

PackageDescription
arkenfoxHardened Firefox user.js preference set
brunoOpen-source IDE for exploring and testing APIs
btopResource monitor for processes, CPU, memory, disks and network
bunJavaScript runtime, bundler, transpiler and package manager
catppuccin-btopCatppuccin theme files for btop
dns-root-hintsIANA DNS root name server hints (named.root)
fblogCommand-line JSON log viewer
gluetunVPN client for multiple providers (Linux only)
iron-proxyEgress proxy for sandboxed agents: allowlisted hosts and secret injection
oh-my-poshPrompt theme engine for any shell
otel-tuiTerminal OpenTelemetry viewer
pipelockAgent egress firewall: forward proxy with hostname, SSRF and DLP checks
pnpm_10Fast, disk-space-efficient JavaScript package manager (10.x)
pnpm_11Fast, disk-space-efficient JavaScript package manager (11.x)
pnpm_12Fast, disk-space-efficient JavaScript package manager (12.x)
nix build .#dns-root-hints

<!-- prettier-ignore -->

PackageDescription
chatgpt-codexOpenAI Codex CLI
claude-codeClaude Code CLI
copilot-cliGitHub Copilot CLI
kimchiKimchi CLI with optional external source-built workflows (ai.kimchi.extensions.workflows)
kiro-cliKiro CLI
kiro-gatewayPython proxy API for Kiro
sembleLocal semantic and lexical code-search CLI

<!-- prettier-ignore -->

PackageDescription
coding-standardsReusable coding standard fragments (DRY, conventional commits, etc.)
delegate-routing-contentPer-runtime model/effort sizing skills and a short routing rule
stacked-workflows-contentSkills, references, and skill-routing fragment

Content packages are derivations with passthru.fragments for composable instruction building.

Feature Matrix

<!-- prettier-ignore -->

FeatureWithout NixHome-ManagerDevEnv
Delegate routingCopy a generated runtime skillai.programs.delegate-routing.enable (Claude + Codex + Kimchi + Kiro)Same; project-native paths
Peer communicationCopy skills/On by default; ai.programs.peer-communication.enable = false or .runtimes.<runtime>.enable = false turns it offSame; project-native paths
Stacked workflow skillsCopy skills/ai.programs.stacked-workflows.enableai.programs.stacked-workflows.enable
MCP server packagesInstall manuallynix build .#<server>nix build .#<server>
Unified MCP configManual native configai.mcpServers.* (all five CLIs)ai.mcpServers.* (all five CLIs)
Typed MCP settingsN/AShared schema + native extensionsShared schema + native extensions
MCP credentialsManual env varsplain, file, or helperplain, file, or helper
Semble search integrationsManual installai.programs.semble (Claude + Codex + Kiro)Same; project-native paths
Git tool packagesInstall manuallyOverlay + nix buildOverlay + nix build
Git configurationgit configgit.settings + typed git.{branchless,absorb,revise}.settings → programs.git.settingsSame options; a repository-local include that wins key by key
GitLab CLI configglab config setglab.*glab.*
GitLab CLI credentialsManual env varsplain, file or helperplain, file or helper
Context and rulesCopy native filesai.{context,rules} (runtime capability-gated)Same; project-native paths. Files a repository commits (AGENTS.md, .github/ instructions) and Kiro steering are read-only copies, not store links
Generated filesN/Aai.formatter, ai.guards.<name>, and ai.checks (Nix-owned build-time files; formatters exclude supplied skill trees, checks include their generated entries; runtime-rendered files excluded)Same; project-native static files included
SkillsCopy native directoriesai.skills.* (all five CLIs)Same; project-native paths
Portable reasoning effortPer-CLI configai.settings.reasoningEffort (Claude + Codex + Copilot + Kimchi)Same; Copilot's lands in .github/copilot/settings.json, which only its interactive session reads, Kimchi's in its project harness settings (see below). Kiro has only per-model native effort
Semantic agentsPer-CLI configai.agents.* (Claude + Codex + Copilot + Kimchi + Kiro)Same; project-native paths
Portable lifecycle hooksPer-CLI configai.hooks.* (Claude + Codex)Same, plus Kimchi's project .kimchi/hooks.json
LSP server configPer-CLI configai.lspServers.* (Claude + Copilot + Kiro)Copilot + Kiro; Claude has no project LSP route (warns); Codex has no native LSP registry
CLI process environmentShell configai.environmentVariables (Codex + Copilot + Kimchi + Kiro)Same; baked into each launcher wrapper, never the shell. Claude uses ai.claude.native.settings.env
Command shellPer-CLI config or $SHELLai.shell / per-runtime shell (ai.kiro.cli.shell for Kiro; Claude + Codex + Kiro)Same; takes a package. Copilot and Kimchi are explicit exclusions
Fragment compositionN/Alib.ai.composelib.ai.compose

Kimchi project delivery

Pooldevenv deliveryBoundary
Contextroot AGENTS.mdAvailable without project trust; reader walks ancestors, but the wrapper remains root-only
MCP servers.kimchi/mcp.jsonRequires project trust and launch from the devenv root
Kimchi settings.kimchi/config.jsonRequires project trust and launch from the devenv root; an owner-only copy. region and telemetry.enabled reach Kimchi through the launcher environment instead
Skills.kimchi/skillsRequires project trust; nearest ancestor wins, but the wrapper remains root-only
Project harness settings.config/kimchi/harness/settings.jsonRequires project trust and launch from the devenv root; user-scope-only keys are rejected during evaluation. ai.settings.reasoningEffort lands here as defaultThinkingLevel, so setting it alone creates the file
Agents.kimchi/agents/<name>.mdRequires project trust and launch from the devenv root; Kimchi's /agents commands cannot edit a declared agent
Permissions.kimchi/permissions.jsonRequires project trust and launch from the devenv root
Hooks.kimchi/hooks.jsonRequires project trust and launch from the devenv root; PermissionRequest is not a Kimchi event and is left out. Home Manager has no user-scope hook file it can own, so shared ai.hooks do not reach Kimchi there (silently) and ai.kimchi.hooks warns

devenv rejects Kimchi's user-scope-only harness settings: defaultProjectTrust, fermentV2, hidePhaseChanges, httpProxy, lastTerminalWarnings, modelMetadata, modelRoles, multiModel, resources, shellProfileApiKeyMigrationDismissed, statusLine. Set those with Home Manager or through Kimchi itself. Every project file is a read-only copy, written only when something is declared; an in-app change Kimchi renames over one is backed up and replaced at the next shell entry.

Kimchi's user-global files live under ~/.config/kimchi, which devenv never writes. Who manages each setting there depends on whether you use Home Manager:

User-global settingHome Managerdevenv only
Harness settings.jsonNix owns the keys it declares inside Kimchi's own file; /model and other in-app writes persistKimchi
mcp.json, permissions.jsonNix, as read-only copies; in-app changes are reset at the next activationKimchi
Project trust (harness/trust.json)Nix (ai.kimchi.projectTrust); defaultProjectTrust = "never", and /trust cannot persist (it may exit)Kimchi's trust prompt
telemetry.enabled, regionNix; telemetry defaults off, region must be declared, and Kimchi reads both from global config.jsonKimchi, unless declared: then the launcher passes the Nix value
skillPathsNix; default skill paths include the ai.* directoryKimchi
API keyNix when ai.kimchi.apiKey is set (read from its secret at launch, so an in-app login has no effect); otherwise /login, which persists in config.json beside the Nix-owned keysSame as Home Manager
Git tokensNix for each host in ai.kimchi.gitTokens (read from secrets at activation), which makes config.json a read-only copy again, so /login stops persisting; Kimchi for the restKimchi
config.json migration, onboarding and survey markersKimchi; they persist beside the Nix-owned keysKimchi
Device idKimchi; none is written while telemetry is offKimchi

Project settings, MCP servers, harness settings, permissions, agents, and hooks resolve under the exact working directory. The devenv wrapper rejects descendant launches instead of silently missing them. Context and skills walk ancestors, so a devenv that declares none of the exact-cwd files leaves the launch directory unrestricted. skillPaths defau

Source 1 files
hooks/register.ts 26 lines
1import type { Register } from "claude-code";
2
3// Probe mod for the delegate map. prompt.compose: appends one session section
4// (COMPOSE-4242) after what the engine composed. prompt.section: appends a
5// SECTION-4343 marker naming each section the engine resolves.
6export const register: Register = (on) => {
7  on("prompt.compose", async ($, e, next) => {
8    const result = await next(e);
9    return {
10      sections: [
11        ...result.sections,
12        {
13          id: "prompt-mw:tail",
14          text: `Compose sentinel: COMPOSE-4242 traits=${e.traits.join(",")}.`,
15          scope: "session",
16        },
17      ],
18    };
19  });
20  on("prompt.section", async ($, e, next) => {
21    const result = await next(e);
22    if (result.text === null) return result;
23    return { text: `${result.text}\n[SECTION-4343 ${e.name}]` };
24  });
25};
26