The Executable Service Manifest & DevSecOps Supervisor
Pinch is a terminal-based process supervisor, developer workflow runner, and declarative governance catalog.
Most software projects suffer from a fundamental disconnect between runtime execution and governance: traditional process runners know how to execute code but ignore ownership, data classification, and SLAs, while enterprise compliance portals capture regulatory metadata in disconnected silos that developers rarely visit after onboarding. Pinch solves this with an executable service manifest (pinch.yaml). The exact same file that supervises your local development background daemons, Docker namespaces, and interactive TUI tasks also serves as your repository's authoritative code contract for operational tiers, data sensitivity, and regulatory applicability.
By uniting runtime supervision with declarative governance, Pinch creates a single source of truth that keeps three critical aspects of your software contract aligned without creating metadata rot:
- Local Execution & Workflows: Zero-friction runtime supervision managing multi-process TUIs, Docker namespaces, file watching, and log tailing in one terminal command (
pinch tui). - Operational Standards & SLAs: Explicit code contracts for service tiers (
tier1totier4), lifecycle status, environment exposures, and container dependencies enforced across repositories. - Regulatory Governance & Tracking: European and Italian compliance applicability (DORA, NIS2, CRA, EU AI Act, GDPR, Garante AdS) tracked alongside code and structurally validated in CI pipelines (
pinch audit).
Because pinch.yaml powers the daily development environment, architecture and governance metadata never go stale, if the manifest breaks, local development breaks.
To enable autocompletion, schema validation, and regulatory applicability tooltips in VS Code, Neovim (yamlls), or JetBrains without any IDE configuration, add this comment as the first line of your pinch.yaml:
# yaml-language-server: $schema=https://raw.githubusercontent.com/optionfactory/pinch/refs/heads/master/schema/pinch-v1.schema.jsonPinch is a local process supervisor, developer workflow runner, and declarative governance catalog. To evaluate Pinch securely, its trust model and execution boundaries must be understood:
Pinch runs locally under the permissions of the invoking user. It does not introduce an elevated daemon, network service, or multi-tenant boundary. If a user executes pinch on their workstation or in a CI/CD pipeline, processes spawn with that user's existing OS privileges and environment variables.
A pinch.yaml manifest is explicitly designed to execute arbitrary shell commands, spawn Docker containers, and interact with local namespaces.
- Never execute an untrusted
pinch.yamlfile. Treat manifests with the exact same security posture as aMakefile,Dockerfile,docker-compose.yml, or.shscript. - Variable Expansion: String interpolation (
{{var_name}}) in commands, environment overrides, and CLI flags is intended to construct dynamic commands. Supplying untrusted user input into variable overrides without external sanitization is outside the intended threat model.
When using type: "docker" or type: "docker-intrude", Pinch passes configured flags (opts, args, --privileged, --net=host, etc.) directly to the Docker daemon. Pinch does not block or deny-list valid Docker flags, as local development and namespace inspection frequently require host-level access. Security boundaries for container execution must be enforced at the Docker daemon or OS level.
The compliance and regulatory metadata blocks (dora, cra, nis2, ai_act, gdpr, and ads) are authoritative declarative governance records. They allow cross-functional teams to assert operational SLAs and regulatory applicability directly alongside runtime definitions. pinch audit verifies structural validity and outputs structured reporting—it is not an automated static analysis engine that legally certifies software resilience or privacy compliance.
Download the latest statically-linked musl executable directly from the GitHub Releases page, or install it via curl:
curl -sSL \
https://github.com/optionfactory/pinch/releases/latest/download/pinch-linux-amd64-musl \
| sudo tee /usr/local/bin/pinch > /dev/null \
&& sudo chmod +x /usr/local/bin/pinchNote: Using processes configured with
type: "docker-intrude"requiresdocker-intrudeto be installed and accessible in your system'sPATH.
Ensure you have the Rust toolchain installed, then clone the repository and build:
git clone https://github.com/optionfactory/pinch
cd pinch
make build-release installPinch uses a structured subcommand hierarchy and global option flags. Global flags can be passed anywhere in your command string.
pinch [OPTIONS] <COMMAND>| Flag | Argument | Default | Description |
|---|---|---|---|
-c, --config |
<FILE> |
pinch.yaml |
Path to the configuration file (PINCH_CONFIG env var supported). |
-o, --override |
<KEY:VAL> |
None | Override a configuration variable (repeatable). |
-h, --help |
None | None | Print help information. |
-V, --version |
None | None | Print version information. |
Launch the full TUI supervisor to manage your processes. If no subcommand is specified, tui is executed by default:
# Run using the default pinch.yaml in the current directory
pinch
pinch tui
# Run using a specific configuration file
pinch -c custom.yaml tui
# Override variables on the fly while launching the TUI
pinch -o env:staging -o target:10.0.0.1 tuiYou can interact with specific processes, inspect configuration variables, or manage Docker networks and images directly from your shell without launching the full TUI dashboard. Commands can be abbreviated
pinch
├── processes
│ ├── ls (list) List all available process names
│ ├── show [NAME] Show the command for a process (or all processes if omitted)
│ └── run <NAME> [-b] Execute a process directly in foreground or background
├── configuration
│ ├── init Generate a default pinch.yaml file
│ ├── show Print the parsed, variable-expanded configuration
│ └── var [NAME] Inspect resolved configuration variables
├── project
│ └── show Show the project metadata block
├── networks
│ ├── ls (list) List all Docker networks defined in the config
│ ├── show [NAME] Show the 'docker network create' command
│ └── create [NAME] Create a Docker network (or all defined networks)
├── containers
│ └── ls (list) List all unique Docker images used in the config
├── audit Inspect project metadata, compliance rules, and container dependencies
└── completion <SHELL> Generate shell completion scripts (bash, zsh, fish)
pinch processes ls [-f, --format <FORMAT>]: Lists all available process names from the configuration.pinch processes show [NAME] [-f, --format <FORMAT>]: Prints the exact command associated with a process name. IfNAMEis omitted, lists all processes in a map format.pinch processes run <NAME> [-b, --background]: Runs the command associated with the name directly in the foreground or background instead of launching the TUI.-b, --background: Spawns the process detached. For processes defined withtype: "docker", this automatically runs the container detached (-d) instead of interactive (-ti).
pinch configuration init: Generates a defaultpinch.yamlfile in the current directory.pinch configuration show [-f, --format <FORMAT>]: Shows the fully parsed and variable-expanded configuration.pinch configuration var [NAME] [-f, --format <FORMAT>]: Inspects resolved configuration variables. IfNAMEis provided, prints only that variable's value; otherwise, prints all variables.
pinch networks ls [-f, --format <FORMAT>]: Lists all Docker networks defined in the configuration.pinch networks show [NAME] [-f, --format <FORMAT>]: Shows thedocker network createcommand for a specific network (or all if omitted).pinch networks create [NAME]: Creates a specific Docker network (or all if omitted) without starting any processes.
pinch containers ls [-f, --format <FORMAT>]: Lists all unique, variable-resolved Docker images used bytype: "docker"processes in the configuration.
# Example: Pre-pull all required Docker images before starting the supervisor
pinch container ls | xargs -r -n1 docker pullpinch audit [-f, --format <FORMAT>]: Prints structured audit metadata combining project identification, governance tiers, regulatory compliance, and resolved container dependencies (defaults tojson).
pinch completion <SHELL>: Supportsbash,zsh, andfish.
# Example: Load completions in bash
source <(pinch completion bash)The process show, process ls, config show, config var, net show, net ls, container ls, and audit commands support multiple output formats via -f, --format <FORMAT>.
| Format | Output Style | Best Suited For |
|---|---|---|
raw |
Unquoted plain text or tab-separated pairs | Shell pipelines (cut, awk, xargs, while read) |
yaml |
Clean YAML formatting | Human reading, configuration auditing |
json |
Structured JSON | Automation and jq integration |
properties |
Standard key=value lines |
Environment file sourcing (export $(pinch config var -f properties)) |
Smart Defaults:
lssubcommands default toraw(flat line-by-line output) for easy shell composition.show [ITEM]defaults torawwhen querying a single item (pinch config var target), oryamlwhen inspecting all items (pinch config var).- Structural commands (
config show,project show) default toyaml.auditdefaults tojson.
Variables defined as {{var_name}} inside your YAML file are resolved using a strict 4-layer precedence hierarchy (highest to lowest priority):
| Priority | Source | Description | Example |
|---|---|---|---|
| 1 (Highest) | CLI -o, --override flags |
Explicit runtime overrides | pinch -o env:prod |
| 2 | YAML vars: block |
Project defaults defined in pinch.yaml |
env: "dev" |
| 3 (Lowest) | Built-in Variables | System path context | {{pwd}}, {{user}}, {{home}} |
# Check the resolved value of a variable
pinch config var target
# Override a variable on the fly
pinch process run simple-ping -o target:1.1.1.1 -o flags:"-c 4"Pinch relies heavily on keyboard navigation. Behavior adapts automatically depending on whether you are managing the grid, viewing global logs, or interacting with a focused TUI application.
| Keybinding | Action |
|---|---|
Ctrl+Q |
Quit Pinch and terminate all child processes. |
Ctrl+A |
Toggle the full-screen "Combined Logs" view. |
Tab |
Cycle focus to the next pane. |
| Keybinding | Action |
|---|---|
s |
Start or Stop the focused process. |
r |
Restart the focused process. |
z |
Toggle Zoom (fullscreen) for the focused pane. |
w |
Toggle line wrap (Log mode only). |
Ctrl+L |
Clear the log buffer (Log mode only). |
Up / k |
Scroll logs up. |
Down / j |
Scroll logs down. |
Left / h |
Scroll logs left (when line wrap is disabled). |
Right / l |
Scroll logs right (when line wrap is disabled). |
PageUp / PageDown |
Scroll logs by 10 lines. |
Enter |
Jump to the bottom of the logs (tail), OR focus the TUI (if in TUI mode). |
If a process is configured with mode: "tui", pressing Enter attaches your keyboard directly to that process.
- While focused, all keystrokes are forwarded directly to the underlying application (
top,vim,htop, etc.). - Press
Ctrl+Xto detach your keyboard from the TUI and return to Grid Navigation.
| Keybinding | Action |
|---|---|
p |
Toggle process name prefixes on/off. |
Up / k |
Scroll combined logs up. |
Down / j |
Scroll combined logs down. |
PageUp / PageDown |
Scroll combined logs by 10 lines. |
Enter |
Jump to the bottom of the combined logs (tail). |
- Focus: Click anywhere on a pane to focus it.
- Scroll: Mouse wheel scrolls up and down through logs.
- Header Buttons: Click the bracketed indicators in a pane's title bar to trigger actions:
[▶]/[■]: Start / Stop (Green / Red)[↺]: Restart (Orange)[↩]: Toggle Wrap / Pending Auto-Restart (Cyan / Purple)[⤢]: Toggle Zoom (Purple)[↗]: Open Link (Electric Blue, visible whenlink:is configured)
Configuration is defined in YAML. You can define global variables, default behaviors, individual processes, and how they should be laid out on the screen.
| Setting | Type | Default | Description |
|---|---|---|---|
schema_version |
Integer | Required | Explicit manifest schema version (must be 1). |
project |
Object | Required | High-level project metadata (name, type, tier, lifecycle, stewards, compliance, auth). |
vars |
Map | {} |
Custom variables (e.g., env: "dev"). Built-ins: {{pwd}}, {{user}}, {{home}}. |
logs_max_size |
Integer | None | Maximum number of log lines to retain in memory per pane. |
shell |
Enum | None | If present, executes commands using the specified shell -c option globally (bash, zsh, fish). |
auto_start |
Boolean | true |
Whether processes start automatically on launch. |
auto_restart |
Boolean | true |
Whether processes restart automatically if they exit. |
grace_period |
Integer | 3000 |
Delay in milliseconds before auto-restarting a process. |
watch_settle_time_ms |
Integer | 800 |
Debounce delay in milliseconds when watching files for changes. |
The project block defines ownership, operational SLAs, security posture, and regulatory compliance rules:
# yaml-language-server: $schema=https://raw.githubusercontent.com/optionfactory/pinch/refs/heads/master/schema/pinch-v1.schema.json
schema_version: 1
project:
name: "Fraud AI Analyzer"
type: service # library | service | tool | job | infrastructure
lifecycle: active # active | maintenance | deprecated | end-of-life | prototype
tier: tier1 # tier1 (24/7 SLA) -> tier4 (experimental)
commissioner: "Acme Financial Services SpA"
channel: "Global Enterprise Integrators Srl"
stewards:
- "mario.rossi@example.com"
authentication:
- jwt
- mtls
- passkey
sensitivity:
- pii
- financial
compliance:
dora: cif-supported # EU Digital Operational Resilience Act
cra: important-class-2 # EU Cyber Resilience Act
nis2: essential-entity # EU NIS2 Critical Infrastructure
ai_act: high-risk # EU AI Act risk classification
gdpr:
role: processor
data_residency: eu
ads: # Italian Garante Privacy 'Amministratore di Sistema'
responsibility: internal
logging: immutable-12-months
nominated: true
latest_audit: "2026-02-10"
environments:
- name: "prod-aws"
type: production
platform: cloud # cloud | datacenter | on-premises | colocation | hybrid | edge
ownership: # infrastructure | operating-system | services | applications
- services
- applications
ingress: restricted-ip
management: restricted-pam
dns: managed # managed | external
domains:
- api.internal.org
- app.internal.org
certificates: managed-acme-dns01 # managed-acme-dns01 | managed-acme-http01 | managed-auto-renew | managed-manual | third-party-provided | third-party-managed | not-applicable- Schema Version (
schema_version): Enforces explicit manifest structure versioning (must be1). - Ownership & References (
stewards,commissioner,channel): Identifies internal subject matter experts/caretakers (stewards), paying clients/entities (commissioner), and channel partners or system integrators (channel). - Service Tiers (
tier): Maps internal operational priority (tier1critical path down totier4prototype). - Data Sensitivity (
sensitivity): Classifies assets handled by the project (public,internal,confidential,restricted,pii,spi,biometric,pci,financial,phi). - European Regulatory Mappings (
compliance):dora: Tracks whether the project supports a Critical or Important Function (cif-supported/non-critical) under EU financial resilience rules.cra: Maps Cyber Resilience Act classes (default,important-class1,important-class-2,critical).nis2: Non-financial critical infrastructure entities (essential-entity,important-entity,out-of-scope).ai_act: Enforces EU AI Act risk classifications (high-risk,general-purpose-ai,limited-risk,minimal-risk,not-applicable).gdpr: Explicitly captures legal processing roles (controller,processor,sub-processor) and geographic data residency boundaries (eu,eea,global).ads: Italian Data Protection (Provvedimento Garante AdS) governance tracking system administrators, immutable access log retention (immutable-6-months/immutable-12-months), formal appointment designation (nominated: true), and annual audit dates (latest_audit: "YYYY-MM-DD").
- Environment Profiles (
environments): Structured list supporting named deployment environments, hosting platforms (platform), stack layer boundaries (ownership), domain ownership (dns), assigned hostnames (domains), TLS certificate lifecycle controls (certificates), and segregated network reachability (ingressandmanagement).
You can define Docker networks in the docker_networks block at the root of your configuration. If only one network is defined, any process specifying a docker-intrude run type will default to it automatically.
docker_networks:
# Simple format (String maps to the subnet)
simple_net_{{env}}: "172.18.0.1/24"
# Detailed format (Object maps to subnet and custom args as a list)
advanced_net:
subnet: "172.19.0.1/24"
args: >
--ipv6
--opt com.docker.network.bridge.enable_icc=falseEach item under processes defines a process to supervise:
name: The name of the process.run: How the process is executed. Supports shorthand strings or detailed objects:- Shorthand (
string): Runs a local command (defaults totype: "process"). - Process (
type: "process"):cmd: The command string to execute.shell: Optional shell override (bash,zsh,fish). Runs the command usingshell -c.
- Docker (
type: "docker"):image: The Docker image to run.opts: Arguments passed todocker run --rm(--name,--network,--ip, etc.).args: Arguments passed to the container entrypoint.
- Docker Intrude (
type: "docker-intrude"):ip: The target IP address in the network namespace.network: (Optional if only one network is defined indocker_networks) The Docker network name.cmd: The command to execute inside the namespace.shell: Optional shell override (bash,zsh,fish). Runs the command usingshell -c.
- Shorthand (
mode: Eitherlog(default) ortui(allocates a PTY for interactive terminal apps).cwd: Working directory (supports variables like{{pwd}}).link: An optional web URL or link associated with this process.watch: A list of file paths. If these files change, the process restarts automatically.auto_start,auto_restart,grace_period,watch_settle_time_ms: Overrides global defaults for this specific process.
# yaml-language-server: $schema=https://raw.githubusercontent.com/optionfactory/pinch/refs/heads/master/schema/pinch-v1.schema.json
schema_version: 1
project:
name: "Fraud-Detection-Service"
type: service
lifecycle: active
tier: tier1
commissioner: "Acme Financial Services SpA"
channel: "Global Enterprise Integrators Srl"
stewards:
- "mario.rossi@company.com"
authentication:
- mtls
- jwt
- passkey
sensitivity:
- pii
- financial
compliance:
dora: cif-supported
ai_act: high-risk
gdpr:
role: processor
data_residency: eu
ads:
responsibility: internal
logging: immutable-12-months
nominated: true
latest_audit: "2026-02-10"
environments:
- name: "production"
type: production
platform: cloud
ownership:
- services
- applications
ingress: restricted-ip
management: restricted-pam
dns: managed
certificates: managed-acme-dns01
domains:
- api.internal.org
docker_networks:
hi: "172.18.23.0/24"
vars:
target: "8.8.8.8"
flags: "-c 10"
processes:
- name: "simple-ping"
run: "ping {{ target }} {{ flags }}"
- name: "system-monitor"
mode: "tui"
run:
type: "process"
cmd: "top"
- name: "nginx"
run:
type: "docker"
image: "nginx:alpine"
opts: >
--name hi-nginx
--network hi
--ip 172.18.23.10
args: "nginx -g 'daemon off;'"
- name: "google-ping"
link: "https://www.google.com"
run:
type: "docker-intrude"
ip: "172.18.23.100"
network: "hi"
cmd: "ping {{ target }} {{ flags }}"Pinch uses a recursive, edge-carving layout system (LayoutNode). Top-level nodes carve percentage slices off screen boundaries, while child nodes recursively split allocated regions into sub-panes.
- Canvas Initialization: Pinch starts with the full terminal grid (
100% width x 100% height). - Sequential Edge Carving: Root nodes specifying an
edge(left,right,top, orbottom) sequentially slice percentages off the remaining outer screen area. - Recursive Sub-Splitting: Nodes with
itemssplit their assigned area horizontally or vertically across child nodes. - Automatic Sizing: When child nodes omit
size, any unallocated space is automatically divided equally among unsized siblings. - Unassigned Panes: Any process not explicitly referenced in the layout is routed to the node marked
unassigned: true(or distributed into leftover center space).
| Field | Type | Description |
|---|---|---|
edge |
top | bottom | left | right |
Carves a percentage slice off the remaining outer terminal bounds. |
size |
integer (0–100) |
Percentage of available space to allocate. Automatically distributed among unsized siblings if omitted. |
direction |
horizontal | vertical |
Split axis for child nodes. Defaults to perpendicular orientation derived from edge. |
name |
string |
Target process name or "combined-logs". |
unassigned |
boolean |
Designates the node as the fallback container for all unassigned process panes. |
items |
list |
Nested list of child LayoutNode elements. |
Layout structures are validated via JSON Schema in your IDE while providing automatic fallbacks in the TUI renderer:
1. Node Variant Rules
IDE schema validation enforces three clean structural node types via oneOf:
- Named Leaf Node: Specifies
name(e.g.,name: "api-server"orname: "combined-logs"). Must not containunassignedoritems. - Unassigned Leaf Node: Specifies
unassigned: true. Must not containnameoritems. - Branch Node: Specifies
itemscontaining a list of sub-nodes. Must not containnameorunassigned.
2. Size & Allocation Limits
- Percentage Bounds: Explicit
sizevalues are expected to be integers between0and100. - Automatic Auto-Sizing: If sibling nodes omit
size, any remaining unallocated percentage after explicitsizedefinitions is divided equally among them.
3. Fallback Container Resolution
- Single Unassigned Block:
unassigned: trueshould be specified at most once per layout. If multiple unassigned containers are declared, the runtime engine captures unassigned processes into the first declared container. - Implicit Center Grid: If
unassigned: trueis omitted entirely, any unallocated process panes automatically populate whatever leftover center space remains after edge carving.
4. Direction & Orientation Defaults
- Top-level nodes specifying
edge: leftoredge: rightdefault their child splitdirectiontovertical. - Top-level nodes specifying
edge: toporedge: bottomdefault their child splitdirectiontohorizontal. - Child branch nodes inside nested
itemsinherit their parent's container bounds and split perpendicular to sibling flow unless an explicitdirectionis defined.
Given this configuration:
layout:
# Step 1: Carve 30% from the LEFT edge (vertical stack of two panes)
- edge: "left"
size: 30
direction: "vertical"
items:
- name: "system-monitor"
size: 50
- name: "cpu-mem-stats"
size: 50
# Step 2: Carve 25% from the BOTTOM edge of remaining space
- edge: "bottom"
size: 25
direction: "horizontal"
items:
- name: "combined-logs"
# Step 3: Unassigned processes ("ping", "disk-usage") fill the remaining center+-------------------+-----------------------------------+
| | |
| System Monitor | Network Ping |
| (30% left / top) | (Unassigned Center) |
| | |
| |-----------------------------------|
| | |
|-------------------| Disk Usage |
| | (Unassigned Center) |
| CPU & Mem Stats | |
| (30% left / btm) |-----------------------------------|
| | Combined Logs |
| | (25% bottom of remaining space) |
| | |
+-------------------+-----------------------------------+
schema_version: 1
project:
name: "MyProject"
type: service
processes:
- name: "system-monitor"
run: "top"
mode: "tui"
- name: "backend-api"
run: "vmstat 1"
- name: "frontend-ui"
run: "vmstat 1"
- name: "database"
run: "vmstat 1"
- name: "cache"
run: "vmstat 1"
layout:
# 1. Carve out 35% from the left edge
- edge: "left"
size: 35
direction: "vertical"
items:
- name: "system-monitor"
size: 40
# recursive sub-split: Divide the remaining 60% vertical area horizontally into sub-panes
- direction: "horizontal"
items:
- name: "database"
- name: "cache" # Omitting `size` automatically splits space 50/50 between database & cache
# 2. Carve out 30% from the bottom of remaining space for logs and unassigned processes
- edge: "bottom"
size: 30
direction: "horizontal"
items:
- name: "combined-logs"
size: 50
- unassigned: true # "backend-api" and "frontend-ui" are automatically placed side-by-side here
size: 50