This is the multi-page printable view of this section. .
Design Notes
- 1: From Human-Friendly to Agent-Native: PIG's CLI Contract
- 2: Compile, Validate, Then Commit: The Native sty conf Pipeline
- 3: The 70% Tuner: Defining the Boundary of pig pg tune
- 4: Why PIG Keeps the Cobra Command Layer Flat
- 5: One Grammar for Dangerous Work: PIG's Operations CLI Safety Contract
- 6: Edit the Declaration, Preserve the Document: Lossless Pigsty Inventory
- 7: Use the CMDB Pigsty Already Has
- 8: A Bounded Grafana Client Instead of Dashboard Shell Scripts
- 9: Let Patronictl Speak for Itself
- 10: PIG 2.0 Product Direction: A Proposal, Not a Release Contract
- 11: Catalog v2 Proposal: Immutable Typed Snapshots Instead of Bigger CSV
- 12: Bootstrapping a Pigsty Controller as a Recoverable Transaction
Design notes explain why PIG behaves the way it does. Each note identifies the decision date, the implementation and release boundary, alternatives that were rejected, and the current user documentation.
These articles are historical and architectural context. For current command syntax and behavior, use the linked PIG documentation; for delivery history, use the release notes.
1 - From Human-Friendly to Agent-Native: PIG's CLI Contract
Decision date: 2026-02-12
Status: Implemented in pig v1.1.0 and refined by later command-layer work.
Current reference:pigcommand overview
Scope: PIG-owned commands and their machine-consumption contract; opaque passthrough commands keep their native interface.
Decision
PIG should be usable by a person at a terminal and by an automation agent without making either consumer parse the other’s presentation. Human-facing text remains concise and operational. Commands that own a stable result expose explicit JSON or YAML results, status codes, and plans. Commands that merely forward an external tool preserve that tool’s native stream, prompts, and exit status instead of wrapping them in a misleading envelope.
Agent-native therefore means a clear capability boundary, not “append JSON to every command.”
Context
PIG began as a convenient package-management CLI. As it grew into PostgreSQL, Patroni, pgBackRest, Pigsty, and repository operations, a human-only interface created several problems:
- automation had to scrape colored prose;
- a zero process exit could hide a failed inner operation;
- destructive workflows could not be inspected before execution;
- an agent had to issue many discovery commands before understanding the host;
- wrappers could accidentally mix subprocess chatter with structured output.
The v1.1.0 design introduced global output selection, stable result objects, execution plans, and
the pig context snapshot. Later refactors narrowed these promises to commands that can actually
own them reliably.
Alternatives considered
Three tempting approaches were rejected:
- Parse human text. It is fragile across wording, localization, colors, and upstream tools.
- Capture every subprocess into JSON. This breaks interactive programs, streaming output, terminal control, and native exit semantics.
- Invent one universal result schema. Package transactions, recovery plans, metrics, and context snapshots have different stable data; flattening them loses meaning.
Contract
The durable contract is:
- text is the default interface for people;
- a command advertises structured output only when PIG owns a stable result;
- structured stdout contains one parseable result, while diagnostics and wrapped-tool output use stderr;
- a plan describes intended actions, scope, risk, and expected effects without performing them;
- destructive PIG-owned operations fail closed when confirmation is missing;
- status codes distinguish usage, confirmation, environment, dependency, and execution failures;
pig contextprovides a bounded environment snapshot rather than forcing consumers to infer it;- passthrough and interactive commands retain the upstream contract.
Consequences
This split makes scripts more reliable and lets agents choose commands based on risk and output capability. It also creates maintenance obligations: every structured field becomes compatibility surface, stdout purity needs tests, and a wrapper must not promise more stability than the tool it delegates to.
The design intentionally allows mixed styles across PIG. Consistency is valuable, but semantic honesty is more valuable than a uniform-looking wrapper.
Verification and evolution
The initial framework shipped with v1.1.0.
The command-layer consolidation in
fb93602 later removed duplicated wrappers and
centralized plan and output glue. Patroni subsequently became a transparent passthrough, an
example of reducing PIG-owned structure when the upstream interface is already authoritative.
Tests now cover structured stdout isolation, result rendering, plan behavior, confirmation gates, and context collection in the packages that own those contracts.
Current status
The principle remains active: use the structured mode documented by a specific command, and do
not infer that global -o can safely transform every external or interactive stream. The current
command surface and supported examples live in the pig reference.
2 - Compile, Validate, Then Commit: The Native sty conf Pipeline
Decision date: 2026-02-18; the production contract was finalized on 2026-08-14.
Status: Implemented and released in pig v1.8.0.
Current reference:pig sty conf
Scope: Generating one validated static Inventory from a trusted Pigsty template; not arbitrary YAML transformation.
Decision
pig sty conf should behave like a small compiler: resolve one safe template, parse it, apply a
bounded set of structural mutations, validate the complete candidate, and atomically commit the
output only after every required stage succeeds.
The command does not invoke the legacy configure script and does not fall back to raw shell
execution. Its structured result reports selected inputs, effective choices, applied change kinds,
and warnings without returning generated secret values.
Context
Template configuration looks simple until paths, symlinks, multiple IP placeholders, version-pinned templates, mirrors, proxy environments, generated credentials, and partially valid YAML interact. A text replacement pipeline can cascade IP substitutions, rewrite unrelated domains, leak secrets, or truncate the destination after a late validation failure.
The output Inventory may contain administrative credentials, so both file handling and result rendering are part of the security boundary.
Alternatives considered
- Call the existing shell configure script. Rejected because parsing, validation, and result semantics would remain outside PIG’s control.
- Use global search and replace. Rejected because IP and domain values need exact placeholder boundaries and simultaneous mapping.
- Write first and validate afterward. Rejected because a failed candidate could replace a usable Inventory.
- Accept arbitrary absolute templates. Rejected because the command should compile known Pigsty modes, not become a privileged file copier.
- Return generated passwords for convenience. Rejected because structured logs and agent traces are not secret-delivery channels.
Contract
- templates resolve below the Pigsty configuration tree through safe relative names;
- absolute paths, traversal, path escape, and direct, symlink, symlinked-parent, or hard-link source/output aliasing are rejected;
- parsing and IP-collision checks precede external preflight;
- placeholder IPs are mapped simultaneously and unrelated addresses remain unchanged;
- domain replacement matches the exact template token;
- profile, region, proxy, locale, and PostgreSQL-version changes are structural and bounded;
- generated credentials use one random value per known identifier and expose only identifiers in results;
- the complete candidate receives native validation and optional bounded Ansible parsing;
- any failure leaves the destination untouched;
- success writes atomically with mode
0600.
Consequences
The command supports a defined family of templates and mutations rather than arbitrary editing.
That limit is deliberate: existing Inventories belong to the lossless pig inventory workflow,
while sty conf owns reproducible compilation from a known template.
Version-pinned templates keep their effective version and warn when a conflicting generic request cannot apply. This is more honest than reporting the requested version while producing another.
Verification and evolution
The native configure direction was first recorded on 2026-02-18. The production refinement landed with
74e084e, and the final contract synchronization
followed in adc4260. Tests cover traversal and
aliasing, simultaneous IP mapping, domain boundaries, interactive and closed-input selection,
version handling, proxy and region changes, secret generation and redaction, preflight ordering,
validation failures, permissions, and atomic writes.
Current status
Use pig sty conf to generate a new Inventory from a Pigsty template and
pig inventory to inspect or edit an existing declaration. Current flags, modes,
and preflight behavior live in the pig sty reference.
3 - The 70% Tuner: Defining the Boundary of pig pg tune
Decision date: 2026-03-21
Status: Implemented on 2026-03-23 and released in pig v1.3.2.
Current reference:pig pg tune
Scope: A deterministic first-pass configuration for one local PostgreSQL instance, not a complete production design service.
Decision
pig pg tune should answer one bounded question: given a CPU count, memory size, disk size, and a
workload profile, what are sensible core PostgreSQL parameters for this machine?
The command targets a “70% correct” starting point. It detects hardware when possible, accepts
explicit overrides, calculates a small set of high-impact parameters, and can write them to
postgresql.auto.conf. It does not claim to design replication, durability, security, logging,
extensions, connection pooling, or workload-specific SQL behavior.
Context
Operators repeatedly need a usable baseline before they have workload telemetry. Copying a static configuration ignores machine size; a full tuning service would need workload traces, storage characteristics, availability requirements, and continuous feedback.
PIG already knows how to locate a PostgreSQL installation and run as the database operating-system user. A small deterministic tuner fits that boundary and remains inspectable.
Alternatives considered
- Ship one universal configuration. Rejected because memory and parallelism settings must scale with the host.
- Build an adaptive autotuner. Rejected because it would require telemetry, experiments, workload classification, and rollback machinery far beyond a local CLI command.
- Rewrite the main configuration file. Rejected because it mixes generated values with distribution- or operator-owned configuration and makes rollback difficult.
- Tune every PostgreSQL parameter. Rejected because many parameters encode business, durability, security, and topology decisions that hardware cannot determine.
Contract
The tuner follows these rules:
- hardware detection is observable and every detected value can be overridden;
- profiles change formulas, not hidden external state;
- calculations are deterministic for the same inputs;
- preview and structured output are available before any write;
- generated settings are confined to the auto-configuration surface;
- existing unrelated settings and comments are preserved by the editor;
- values remain bounded by PostgreSQL and machine constraints;
- the output states the assumed SSD storage model and the limits of the recommendation.
Consequences
The command is useful for development machines, fresh installations, and initial sizing, but it must not be treated as proof that a production database is tuned. Replication lag, checkpoint behavior, query concurrency, cache hit rates, storage latency, extensions, and failure objectives still require measurement and operator judgment.
Keeping the scope small also makes the formulas testable and lets users reproduce a result without a remote service.
Verification and evolution
The implementation landed in
60eecfe
and was tagged as v1.3.2. Unit tests cover profile calculations, hardware overrides, result
rendering, and safe postgresql.auto.conf editing. Static-analysis cleanup followed without
changing the product boundary.
Current status
pig pg tune remains a first-pass tool. Review its output before applying it and use Pigsty or a
workload-specific tuning process when topology, high availability, observability, or security must
be designed together. Current flags and examples are maintained in the pig pg reference.
4 - Why PIG Keeps the Cobra Command Layer Flat
Decision date: 2026-06-30
Status: Active repository architecture.
Current reference:pigcommand overview and the source repository
Scope: Go source ownership and command registration, not the public command taxonomy itself.
Decision
The cmd package stays flat. One top-level command belongs in one top-level Go file: pg.go,
pb.go, pt.go, pe.go, sty.go, do.go, repo.go, and their peers. Even large command trees
remain in that entry-point file unless there is an explicit decision to change the layout.
The file may be long, but it should contain Cobra concerns: names, aliases, annotations, flags,
argument validation, help, registration, and option mapping. Concrete work belongs in cli/*,
internal/*, or another implementation package.
Context
Earlier command growth produced many small files named after subcommands and several parallel implementations of confirmation, structured output, plan rendering, and legacy wrapping. It became difficult to answer simple questions: where is a top-level command registered, which file owns an alias, and whether two helpers implement the same policy.
PIG’s command families are large, but their public grammar is one surface. Keeping that grammar in one place makes review and collision detection easier, while implementation packages remain decomposed by responsibility.
Alternatives considered
- A directory per command under
cmd. Rejected for normal commands because it scatters one public grammar across many packages and encourages business logic near Cobra. - One file per subcommand. Rejected because registration, aliases, and inherited flags become hard to audit as one contract.
- Put everything in
cmd. Rejected because tests, reuse, and error handling suffer when operational logic depends on Cobra state. - Abstract every repeated line. Rejected because speculative frameworks can hide the command grammar; only stable, cross-command glue should be shared.
Contract
cmd/root.goowns root setup, global flags, and top-level registration;cmd/utils.goowns shared command-layer helpers;- each normal top-level command has one matching top-level source file and may have one matching test file;
- Cobra code validates syntax and maps options, but does not perform the operation;
- reusable confirmation, annotation, structured-output, and plan helpers have one implementation;
- implementation packages accept ordinary options and return typed results or errors without depending on Cobra globals.
Consequences
Some command files are intentionally large. The trade-off is accepted because the public surface can be reviewed as a unit, while the implementation remains split below it. The rule also reduces file churn when aliases or flags move and gives agents a deterministic starting point.
The boundary is architectural, not cosmetic: a short cmd file that hides business logic in
closures is still a violation, while a long file containing only declarative command glue is not.
Verification and evolution
The convention was recorded in
9eb70db, followed by the large command-surface
consolidation in fb93602. Guard tests check alias
collisions and command registration, while package tests exercise the implementation beneath the
Cobra layer.
Current status
This remains the repository rule for new work. Public command documentation belongs on this site; source-layout enforcement remains close to the code so contributors and coding agents encounter it before editing.
5 - One Grammar for Dangerous Work: PIG's Operations CLI Safety Contract
Decision date: 2026-07-02
Status: Released forpg,pb,pt, andpitrby v1.5.0; the 2026-08-29doandbuild proxyrefinements were released in v1.8.1.
Current reference:pig pg,pig pb,pig pitr,pig do, andpig build
Scope: PIG-owned operational commands; transparent upstream commands retain upstream confirmation and exit behavior.
Decision
Operational convenience must not blur operational meaning. PIG distinguishes low-level primitives from multi-stage orchestrators, makes destructive intent explicit, reserves aliases carefully, and requires plans and structured results to describe the same action that text mode will execute.
The most important example is recovery: pig pb restore is the pgBackRest primitive, while
pig pitr coordinates Patroni, PostgreSQL shutdown, restore, restart, and post-recovery guidance.
An alias must never make those two paths look interchangeable.
Context
The first generation of convenience aliases accumulated inconsistent positional arguments,
confirmation flags, output handling, and service semantics. Similar words such as restart,
restore, promote, and failover can refer to very different layers. A short alias that crosses
those layers can turn a harmless-looking invocation into an unmanaged destructive primitive.
Automation also exposed false-success risks when wrapper output, subprocess output, and result rendering used different definitions of success.
Alternatives considered
- Maximize shorthand aliases. Rejected because collisions and cross-layer synonyms are more dangerous than a few saved characters are valuable.
- Put confirmation on every risky-looking word. Rejected for passthrough commands because the upstream tool must own its prompt and semantics.
- Make the orchestrator call a convenience alias of the primitive. Rejected because recovery coordination has additional stop, verification, and restart invariants.
- Return success after launching the inner command. Rejected because the result must reflect the complete owned workflow.
Contract
- sibling command names and aliases are unique;
- an alias cannot shadow a different top-level command;
- destructive PIG-owned operations require explicit confirmation and support non-mutating plans where a meaningful plan exists;
- command-layer validation rejects malformed or extra positional arguments before side effects;
- command-specific names mirror the downstream Pigsty contract, or use the narrowest documented safe boundary when the downstream playbook has no explicit grammar;
- structured output and text mode share one result and one success definition;
- credential-bearing values stay out of diagnostics, and readiness or connectivity failure remains a command failure rather than a logged warning followed by success;
- low-level restore does not claim to manage Patroni or HA routing;
- the PITR orchestrator stops the manager when required, proves PostgreSQL is stopped, restores, optionally starts PostgreSQL, and deliberately leaves Patroni stopped for operator verification;
- native tools receive extra arguments only through an explicit, documented boundary.
Consequences
Some historical shorthand disappeared and some scripts had to adopt cluster-first or explicit target syntax. In return, command names now preserve layer boundaries, plans correspond to real actions, and recovery automation cannot silently substitute a primitive for the orchestrator.
The contract does not eliminate operational risk. It makes risk visible and keeps a convenience layer from inventing ambiguity.
Verification and evolution
The normative command specifications entered the repository in
c62c0f5. Subsequent commits aligned aliases,
early validation, restore targets, service semantics, and role detection. Guard tests traverse the
Cobra tree to reject sibling and cross-layer alias collisions. Recovery tests cover plan,
confirmation, stop escalation, side restores, restart behavior, and structured failure results.
Patroni later moved to transparent passthrough. That refinement keeps the same safety principle: PIG owns safeguards only for workflows it owns.
The same contract was applied to pig do name and cluster validation in
3e1603b,
with Ansible built-in targets closed in
a880485.
Package-backed, credential-safe, truthful build proxy setup entered in
220ef9c,
followed by structured-argument redaction and corrected machine annotations in
74cb128,
and optional operands were reflected in the machine grammar in
de7ffd0.
The changes were exercised on Ubuntu 24.04 and Rocky Linux 9 ARM64 Farrow guests, then released
from source commit e3d1eb4
after the v1.8.1 CI run passed.
Current status
Use pig pb restore when you intentionally want the pgBackRest primitive and pig pitr
when you want the managed recovery workflow. Current syntax, warnings, and platform requirements are
maintained in the command reference pages rather than frozen in this historical record.
6 - Edit the Declaration, Preserve the Document: Lossless Pigsty Inventory
Decision date: 2026-07-18
Status: Implemented and released in pig v1.6.0.
Current reference:pig inventory
Scope: Static Pigsty Inventory inspection, scoped editing, validation, comparison, and safe writes.
Decision
PIG treats pigsty.yml as both a semantic declaration and a human-maintained source document.
Semantic parsers determine what the Inventory means; the original bytes remain authoritative for
how it is written. Scoped edits replace bounded source ranges and then reparse the complete
candidate before an atomic write.
This avoids a common YAML-tool failure: a logically correct edit that silently rewrites comments, key order, quoting, anchors, block scalars, or line endings across the entire file.
Context
Pigsty Inventories are long-lived operational assets. They contain topology, tuning, credentials, comments, examples, anchors, and locally meaningful ordering. A conventional parse-mutate-serialize cycle can produce a valid but unreviewable diff and may change constructs the operator never selected.
At the same time, raw text editing without semantic validation can put invalid or contradictory configuration on disk. The design needed source fidelity and whole-document correctness together.
Alternatives considered
- Round-trip through one YAML serializer. Rejected because no selected serializer preserved the full source contract byte-for-byte across the real Pigsty corpus.
- Use regular expressions for YAML. Rejected because quoting, comments, aliases, block scalars, and nested collections make text-only semantic decisions unsafe.
- Edit only a normalized generated copy. Rejected because the active Inventory is operator-owned and would still diverge from the generated representation.
- Allow every node type to be replaced. Rejected because anchors, aliases, tags, and block scalars need stricter handling than ordinary mappings and scalars.
Contract
- duplicate keys and multi-document YAML are rejected;
- selectors address one unambiguous declaration fragment;
- semantic decoding and source-range discovery are separate concerns;
- an edit starts from the exact source revision and fails if the file changes concurrently;
- the edited fragment is normalized only as required for its insertion context;
- the complete candidate is reparsed and validated before commit;
- writes use a same-directory temporary file, sync, rename, and directory sync;
- symlink and unsafe path changes are rejected;
- a successful edit tightens secret-bearing Inventory permissions to
0600; - diagnostics, diffs, plans, and structured results omit declaration values unless a command is explicitly a raw text surface.
Consequences
The editor is more complex than ordinary YAML marshaling, and some syntactically valid fragments are deliberately refused when source fidelity cannot be proven. The benefit is a reviewable diff: unselected parts of the Inventory remain byte-for-byte stable, invalid YAML cannot be committed, and a concurrent edit cannot be overwritten silently.
show remains intentionally secret-bearing. That explicit exception is safer than pretending a
partial redactor can classify every future credential key.
Verification and evolution
The root Inventory contract and existing-CMDB boundary were established in
ba6e678, with the implementation landing in
ea43858. Tests exercise real Pigsty configuration
corpora, byte-identical round trips, scoped replacement, protected YAML forms, concurrent-change
rejection, atomic-write failures, selectors, validation, and secret-free diagnostics.
Later refactors removed legacy options and separated validation stages without changing the source-fidelity model.
Current status
The static Inventory remains the primary declaration surface. Use the current
pig inventory reference for selectors, validation profiles, structured output, and
the explicitly experimental CMDB bridge.
7 - Use the CMDB Pigsty Already Has
Decision date: 2026-07-18
Status: The greenfield revision store is superseded; the thin existing-CMDB adapter is implemented and remains experimental.
Current reference:pig inventory cmdb
Scope: Exchanging declarations with Pigsty’s existing CMDB, not designing another configuration database.
Decision
PIG must reuse the CMDB already provided by Pigsty. Its responsibility is a bounded adapter: validate a static Inventory, load declarations into the existing tables, dump the existing projection, check consistency, and switch Ansible between the static and dynamic sources safely.
PIG does not own a second schema, migration history, snapshot ledger, compare-and-swap revision store, three-way merge engine, or rollback database.
Context
An early design treated CMDB support as a greenfield backend. It proposed a separate schema,
immutable snapshots, revision tokens, merge and rollback operations, backup bundles, and source
switch records. The design was internally coherent but started from the wrong premise: Pigsty
already had the pigsty and pglog schemas, load scripts, dynamic Inventory projection, and source
switching behavior.
Building a parallel control plane would duplicate facts, create synchronization problems, and make PIG responsible for a data model owned by another project.
Alternatives considered
- Keep the new revision store as an advanced mode. Rejected because two authorities are still two authorities, even if one is optional.
- Mirror between the new and existing schemas. Rejected because conflict resolution and migration would become permanent product responsibilities.
- Hide the existing scripts behind a shell wrapper. Rejected because PIG needs bounded timeouts, safe connection handling, structured plans, and atomic source switching.
- Remove CMDB support entirely. Rejected because a small native adapter adds useful validation and automation without redefining the schema.
Contract
- Pigsty’s existing schema and projections are the data-model authority;
- PIG connects through an explicit database target, environment configuration, or
service=meta; - credentials, DSNs, SQL bodies, and declaration values never enter plans or diagnostics;
checkis read-only;initapplies the existing baseline and does not claim to back up an existing database;loadreplaces declaration rows transactionally and requires explicit confirmation;dumprefuses an unexpected overwrite unless forced;enableanddisableedit only recognized Ansible Inventory source forms and write atomically;- unfamiliar executable Inventory sources are refused rather than rewritten;
- the entire command family remains labeled experimental.
Consequences
The correction deleted a large amount of already implemented revision-store code. That deletion was intentional scope recovery, not lost functionality: the removed features described a product PIG should not own.
The remaining adapter is smaller, easier to audit, and compatible with existing Pigsty operations.
It also inherits the limits of that system: init needs an operator-managed backup, and loading a
declaration set is a replacement operation rather than collaborative version control.
Verification and evolution
The corrected boundary was recorded in
ba6e678. The abandoned implementation was removed
in e0f73ed, deleting the parallel schema, snapshot,
merge, revision, and rollback machinery. Tests for the retained path cover PostgreSQL compatibility,
connection redaction, transaction failures, digest-pinned confirmation, dump safety, and atomic
source switching.
Current status
The existing-CMDB adapter shipped in v1.6.0 but remains experimental.
Operators should back up real CMDB state before initialization or replacement and use the current
pig inventory documentation rather than the historical abandoned design.
8 - A Bounded Grafana Client Instead of Dashboard Shell Scripts
Decision date: 2026-07-18
Status: Implemented in v1.6.0; Grafana dashboard schema v2 support followed in v1.6.2.
Current reference:pig sty grafana
Scope: Pigsty-owned dashboard folders, dashboards, and UI preferences; not general Grafana provisioning.
Decision
PIG should manage the Grafana assets that ship with Pigsty through a bounded native HTTP client. It may inspect readiness, list managed assets, load or initialize dashboards, dump them, remove only owned dashboards, and adjust the supported language and style preferences.
The command must not grow into a general Grafana administration API. Datasources, organizations, users, arbitrary folders, plugins, and unrelated dashboards remain outside its ownership.
Context
Legacy dashboard workflows were tied to scripts and local file layout. They offered little structured evidence about which endpoint was contacted, what assets were owned, or why a partial failure occurred. At the same time, calling the full Grafana API without a narrow ownership model could delete user content or expose credentials in arguments and diagnostics.
A native client was justified only if its network, authentication, ownership, and result boundaries were explicit.
Alternatives considered
- Keep shell scripts as the public interface. Rejected because timeout, redirect, response-size, redaction, and structured-result behavior would remain inconsistent.
- Expose arbitrary Grafana API calls. Rejected because it would make PIG a second Grafana CLI without a stable product boundary.
- Delete by folder name alone. Rejected because names are not sufficient proof of ownership.
- Embed a demo password. Rejected because default credentials become long-lived secrets and encourage unsafe automation.
Contract
- every request has bounded connection and response behavior;
- unsafe redirects and oversized responses are refused;
- public health is checked before authenticated operations;
- credentials come from explicit safe inputs, environment, or Inventory resolution, with no embedded default password;
- command-line passwords are documented as an emergency path because argv and shell history may expose them;
- errors and structured results never contain credentials or response bodies;
- load and init operate on Pigsty’s known dashboard bundle;
- clean removes only assets proven to be PIG/Pigsty-owned;
- language and style accept a fixed vocabulary and map
autoto Grafana’s system preference; - schema v1 and schema v2 dashboard representations are normalized at the client boundary.
Consequences
The native client produces better plans, error classification, and automation results, but it must track the small Grafana API surface it owns. Supporting a new dashboard schema is acceptable; supporting unrelated Grafana resources is not implied.
Operators can use another Grafana client for general administration without PIG claiming authority over those resources.
Verification and evolution
The native dashboard workflow landed in
3060485. Tests cover health, authentication,
timeouts, redirects, size limits, ownership checks, preference requests, redaction, partial
failures, and load/dump behavior. Dashboard schema v2 support followed in
67f6e3b and shipped in v1.6.2.
Current status
pig sty grafana is the supported PIG entry point for the bounded Pigsty dashboard lifecycle.
Use the current pig sty reference for commands and credentials; use Grafana-native tools
for resources outside this ownership boundary.
9 - Let Patronictl Speak for Itself
Decision date: 2026-07-21
Status: Implemented and released in pig v1.6.0.
Current reference:pig pt
Scope: Patronictl-backed cluster commands plus PIG-owned configuration selection, settings sugar, service, status, and log helpers.
Decision
pig pt is a transparent launcher for the installed patronictl. PIG selects the configuration
and dispatches a small set of local helpers. Every other command token and all following arguments
are passed unchanged, with native prompts, terminal behavior, output formats, and exit codes.
PIG no longer maintains a copy of Patronictl’s evolving command tree.
Context
Mirroring Patronictl required PIG to reproduce commands, options, positional grammar, confirmation,
formatting, and version-dependent behavior. That surface changed upstream and PIG’s copy drifted.
Users could receive different semantics depending on whether they called patronictl directly or
through PIG.
The wrapper still adds value in a Pigsty environment: selecting the correct config as the database operating-system user, providing local service and log workflows, and translating a small settings operation into one native edit-config call.
Alternatives considered
- Continue mirroring every upstream command. Rejected because it guarantees lag and duplicates validation that Patronictl already owns.
- Allow only a tested command allowlist. Rejected because new upstream commands would remain unavailable until a PIG release.
- Capture native output into PIG JSON. Rejected because it breaks interactive editing, streaming, prompts, terminal fidelity, and upstream schemas.
- Remove
pig ptentirely. Rejected because deterministic config selection and local Pigsty helpers remain useful.
Contract
- the first non-option command token determines local dispatch or passthrough;
set, local service shortcuts,status, andlogare PIG-owned;- all other commands and remaining tokens are forwarded verbatim;
pig pt -- COMMAND ...bypasses a local-name collision explicitly;- wrapper-level options must precede the native command token;
- native help can run without resolving a local Patroni configuration;
- Patronictl owns interactive prompts, native
--format, and exit codes; - global PIG structured output is rejected where it would consume a native option ambiguously;
- the selected config is resolved predictably and the process runs as the database system user.
Consequences
Automation had to adopt Patronictl’s cluster-first positional grammar and native output flags. Some PIG-only aliases and result schemas disappeared. In exchange, new Patronictl features work without a PIG release and behavior no longer depends on a lagging wrapper implementation.
The local set helper remains intentionally small: it classifies scalar Patroni keys and
PostgreSQL parameters, then performs one native edit-config action.
Verification and evolution
The rewrite landed in
6cbc23b. Tests cover token-boundary parsing,
verbatim argv preservation, config precedence, database-user execution, native exit propagation,
help without configuration, output-mode rejection, the -- escape, and local-helper collisions.
The final help-path refinement landed before v1.6.0.
Current status
Use Patronictl’s own documentation for forwarded command grammar and pig pt for PIG’s
config selection and local helpers. Do not assume PIG -o json can replace Patronictl’s native
--format json.
10 - PIG 2.0 Product Direction: A Proposal, Not a Release Contract
Decision date: 2026-08-13
Status: Proposal for owner review; it is not implemented and is not a PIG 2.0 release commitment.
Current reference: PIG documentation and the current v1.8.1 release
Scope: Candidate product boundaries and verification gates for a future PIG 2.0 / Pigsty 5.0 line.
Decision
The proposed direction makes PIG the stable onboarding front door from an empty controller to a validated, deployable Pigsty Inventory. PIG would own Catalog selection, resolution, plans, bounded execution orchestration, structured results, and redacted receipts. It would continue to delegate package transactions, configuration application, and infrastructure state to DNF/APT, Ansible, and future provider-specific tools.
The proposal deliberately preserves PIG’s standalone value: repo, ext, and install must work
without a Pigsty project. It also preserves explicit deployment consent: a future pig sty setup
may download, bootstrap, and configure, but it must stop before multi-node deploy unless the user
invokes deployment separately.
Context
By v1.8.0 PIG could download releases, bootstrap a controller natively, compile Inventory, manage repositories and extensions, and run selected operations. Several product seams remained:
- repository, package-alias, extension, route, and Pigsty metadata could change independently;
- projects had no explicit Catalog identity to protect later resolution from global updates;
- route choice and repository safety were not one visible product contract;
- execution results did not yet form a durable, redacted receipt across the onboarding path;
- compatibility among PIG, Pigsty, Catalog schema, operating systems, and Ansible needed one release matrix rather than separate assumptions.
The proposal treats those seams as the 2.0 problem. It does not use the major version as permission to rename commands or rebuild tools that already have an authority.
Alternatives considered
- Turn PIG into a monolithic configuration and state engine. Rejected because Inventory, Catalog authoring, package managers, Ansible, and providers already own different facts.
- Make Pigsty depend on a live PIG or pgext checkout. Rejected because a Pigsty release must remain independently usable from generated, versioned artifacts.
- Make setup deploy automatically. Rejected because creating and validating configuration is a different consent boundary from changing remote nodes.
- Reimplement DNF/APT failover or Ansible execution. Rejected because PIG should select inputs and explain results, not become another package manager or configuration engine.
- Block 2.0 on Vagrant/Terraform unification. Rejected because lab providers have different state semantics and do not determine the core onboarding path.
- Invent a universal
sty planimmediately. Rejected until at least two owned workflows prove that one reusable plan schema exists.
Contract
If accepted, the product direction would enforce these boundaries:
- each fact type has one authority: Inventory for cluster declarations, Catalog authoring sources for product metadata, project lock for selected snapshot identity, receipts for observed results, and providers for live state;
- PIG owns Catalog schema, validation, client, resolver, and selection, but not every authoring database;
sty setupcomposes existing init, boot, and configure use cases instead of duplicating them;- setup stops after a validated Inventory; deploy remains explicit;
- standalone commands follow a compatible Catalog channel, while a Pigsty project pins its selected snapshot after a successful setup or configuration commit;
- ordinary commands never rewrite an existing project lock implicitly;
- route selection is explicit or a bounded first-run decision, not a continuous GeoIP, cloud-IMDS, or background-latency service;
- package download retry and endpoint failover remain owned by DNF/APT;
- execution artifacts are versioned and redacted; raw upstream modes preserve native streams and exit behavior;
- doctor remains diagnostic and does not gain default repair authority;
- future lab support is a thin adapter and never makes PIG the owner of Terraform state.
Consequences
The proposal creates a clearer first-run story and makes metadata selection auditable. It also adds new durable contracts: snapshot identities, project locks, migration rules, trust policy, receipts, and compatibility matrices. Those contracts increase the testing and release burden and must not ship as loosely coupled features.
Some attractive work is intentionally optional or deferred. An Ansible event bridge is a target only if redaction and compatibility experiments pass. Doctor/support bundles and lab adapters are post-GA. EL7 support remains an owner decision rather than an implied compatibility promise.
Verification and evolution
This proposal requires evidence before it can become a release contract:
- a native onboarding VM matrix across the declared Linux targets;
- adversarial Catalog signature, expiry, rollback, mix-and-match, and offline tests;
- semantic-diff proof that generated Pig, Pigsty, and pgext consumers do not drift;
- an Ansible callback experiment with zero
no_logor secret leakage; - route-selection tests for global, China, proxy, and restricted-network environments;
- repository-signing tests before secure defaults are changed;
- rehearsed 1.x-to-2.0 layout, lock, and mixed-version migration;
- schema and structured-output fixtures tied to an explicit compatibility matrix.
The current implementation baseline is
v1.8.0.
That release contains native boot and configure, but it does not implement the proposed Catalog v2,
project pin, setup command, event receipt, or 2.0 migration contract.
Current status
This is a public proposal record, not an announcement. Current users should follow the v1.8.1 documentation. Catalog v2 security selection, typed overlays, path layout details, EL7 support tier, event-bridge viability, and the final 2.0 scope still require explicit decisions and experimental evidence before implementation or release claims are appropriate.
11 - Catalog v2 Proposal: Immutable Typed Snapshots Instead of Bigger CSV
Decision date: 2026-08-13
Status: Pre-implementation proposal; security mechanism, overlay scope, packaging, and path ADRs remain open.
Current reference:pig extandpig repodescribe the v1 Catalog behavior.
Scope: A candidate PIG 2.0 publication and consumption model for product metadata, not Inventory or live system state.
Decision
Catalog v2 should be one immutable, verifiable snapshot composed of multiple typed targets. A manifest binds platform, repository, route, package-alias, extension, compatibility, Pigsty release, and public-key metadata to exact bytes. Candidate targets are validated together and activated through one pointer, preventing a new repository catalog from being mixed silently with an old extension matrix.
The snapshot digest is its identity. Package, system, user, portable, and project scopes store or select the same verified content; they do not merge unrelated base snapshots into a synthetic Catalog.
Context
The v1 Catalog is practical but spreads related facts across embedded CSV, repository YAML, Pigsty variables, generated sites, and reload paths. Some fields repeat derived information, and the extension matrix compresses several independent identities into one record. Independent updates make it difficult to prove that repository, package, extension, and compatibility data belong to the same publication event.
Catalog v2 is therefore a publication and trust problem, not merely a new serialization format.
Alternatives considered
- Create a larger
extension.csvor one giant YAML file. Rejected because unrelated target types evolve differently and cannot be activated or streamed independently. - Use SQLite, protobuf, or a custom binary matrix immediately. Rejected because the current dataset has not demonstrated a performance need that justifies a new runtime and debugging cost.
- Merge system, user, and project base snapshots field by field. Rejected because the result has no single publisher, digest, compatibility statement, or signature.
- Store active or project-pinned content only in a cache. Rejected because deleting a cache must not destroy a durable user or project decision.
- Let a user file shadow the official trust root. Rejected because security policy is a constraint, not an ordinary last-writer-wins preference.
- Silently update and activate in the background. Rejected because metadata changes can alter package resolution and must be an observable operation.
Contract
The proposed snapshot contract is:
- deterministic UTF-8 JSON for manifests and small targets, and JSONL for large sparse targets;
- raw manifest bytes and target length/hash are verified without parse-and-reserialize ambiguity;
- manifests carry schema, monotonic security version, creation, expiry, channel, and PIG/Pigsty compatibility;
- an embedded rescue baseline is always available;
- package-owned baselines, durable snapshot stores, mutable state pointers, and purgeable download caches are separate paths;
- Linux follows FHS/XDG, macOS uses Application Support and Caches, and portable
PIG_HOMEkeeps config, data, state, cache, and run roles distinct; - a project lock records snapshot identity and ordered overlays, while the verified snapshot is materialized into durable project support data;
- selecting a digest and finding its bytes are separate algorithms;
- system security policy can only be tightened by lower scopes, not weakened silently;
- updates download into private staging, verify every layer, sync, move into a content-addressed store, and atomically replace the active pointer;
- failures retain the previous active snapshot;
- project pins do not move when user or system active channels update;
- offline export includes verification metadata and public trust material, never private keys;
- old
ext reloadandrepo reloadmay map to one whole-snapshot update for one compatibility period, but cannot activate targets independently.
The runtime Catalog excludes Inventory, credentials, live probes, installed-package state, Ansible events, provider state, confirmations, and metrics that change without a product decision.
Consequences
Typed targets make ownership and validation clearer, and content addressing makes rollback and airgap import auditable. Project materialization prevents a deployment from depending on one user’s global cache. Independent OS packages can refresh a read-only baseline without changing an active user selection.
The cost is a larger release protocol: key rotation, expiry, rollback protection, garbage collection, path permissions, migration, package-manager lifecycle, overlay conflicts, and cross-repository generators all become compatibility-sensitive work.
The extension model must also separate SQL extension identity, upstream project, distribution or
build unit, versioned release, OS package offer, target availability, and display policy. Derived
fields such as aggregate platform support or required_by should be generated, not maintained as a
second truth.
Verification and evolution
Before implementation, the proposal requires an ADR to choose between go-tuf and a minimal signed manifest. Both candidates must pass the same threat tests: bad signatures, expired metadata, rollback, target substitution, mix-and-match snapshots, truncated downloads, and offline verification. If neither passes, Catalog v2 cannot be a 2.0 release feature.
Additional gates cover FHS/XDG/macOS/portable paths, root and non-root permissions, read-only homes and projects, symlink replacement, disk-full and concurrent activation, package upgrade/remove semantics, project survival after global-cache deletion, and parity migration of the current extension and availability corpus.
The current source baseline remains
v1.8.0,
whose embedded and reloadable v1 Catalog continues to define released behavior.
Current status
No Catalog v2 command, manifest, trust root, store layout, project lock, or migration format is a
released PIG contract today. Typed overlays should be omitted from 2.0 if their conflict and trust
rules cannot be proven; a complete custom signed channel is safer than loose unverified patches.
Current installation and catalog behavior remains documented under pig ext and
pig repo.
12 - Bootstrapping a Pigsty Controller as a Recoverable Transaction
Decision date: 2026-08-14
Status: Implemented and released in pig v1.8.0.
Current reference:pig sty boot
Scope: Preparing a Pigsty controller and its package sources; not deploying a database cluster.
Decision
pig sty boot should be one native, failure-aware controller bootstrap workflow. It resolves an
explicit source before privilege elevation, prepares online or offline repositories, installs only
the required controller packages, proves Ansible is usable, and performs bounded finishing checks.
Repository replacement is transactional: definitions are backed up and restored when package setup fails. Optional conveniences may warn, but invalid explicit input, package failures, and an unusable final Ansible environment are hard failures.
Context
The previous command delegated to a shell bootstrap script. That made source selection, download,
sudo boundaries, repository rollback, error classification, and structured automation difficult to
observe. A present ansible-playbook binary could also be mistaken for a usable environment even
when its Python dependencies were missing.
Offline installations added another ambiguity: an already ready controller may still need a local repository prepared for later nodes.
Alternatives considered
- Continue invoking the legacy script. Rejected because PIG could not own the transaction or explain partial failure reliably.
- Require the entire command to start as root. Rejected because explicit downloads and source validation do not need privilege and should happen before one bounded elevation.
- Treat an Ansible binary as readiness. Rejected because the executable may use a Python environment missing required modules.
- Skip repository work when Ansible is ready. Rejected because staging an explicit offline source is an independent requested effect.
- Make every finishing check fatal. Rejected because locale convenience, localhost SSH repair, or tree initialization can fail without invalidating an otherwise usable controller.
Contract
- explicit local paths and URLs are validated and never silently fall back to online mode;
- automatic offline sources must pass ownership and permission checks;
- a committed local repository can take precedence over a selected package;
- download and restricted archive extraction use native bounded implementations;
- offline bundles require a
pigsty/repo_completesentinel; additional roots are preflighted and renamed beforepigsty, while conflicts and interrupted residue fail closed for manual cleanup; - privilege elevation happens once after source resolution and can be disabled or made non-interactive;
- overwritten repository definitions are recoverable on setup failure;
- readiness executes Ansible and checks the Python modules it will use;
- the result distinguishes ready, offline, online, and existing modes;
- hard failures and finishing warnings are separate structured fields;
- bootstrap does not claim that Pigsty deployment has succeeded.
Consequences
The native workflow is larger than a script launcher, but its side effects and rollback state are visible. It can stage offline content on an already usable controller and gives automation a stable result without hiding optional problems.
The command still cannot prove a deployed Pigsty environment. Controller readiness, Inventory generation, deployment, and live service validation remain separate gates.
Verification and evolution
The native implementation landed in
222616e and was refined in
74e084e. Tests cover source precedence,
permission checks, restricted extraction, sudo re-exec, repository rollback, locale recovery,
Ansible/Python readiness, localhost SSH, initialization, warning classification, and structured
results. The release page records delivery in v1.8.0.
An unreleased post-v1.8 refinement extends the offline bundle path to preserve multiple safe top-level repositories. It keeps the existing sentinel contract and deliberately does not add a manifest or recovery journal. This refinement is implemented and locally tested, but is not part of the v1.8.0 release claim above.
Current status
pig sty boot prepares the controller; it does not run deploy.yml or prove database services.
Use the current pig sty documentation for source modes, environment controls, and next
steps.