Files
sasa e7e728cd23 Add OpenAI specific configuration
- add AGENTS.md and PLANS.md based on MPV
- add subagents configuration
2026-10-11 23:06:05 +03:00

15 KiB

AGENTS.md

Scope

  • These rules apply to the entire repository.
  • Build a local WireGuard management tool for Linux servers.
  • Keep wg-manager.sh as the primary entry point.
  • The project is copied as a directory and is not installed into PATH.
  • Do not add installer or uninstaller scripts unless explicitly requested.
  • Treat MVP.md as the product scope and acceptance reference.
  • Treat PLANS.md as the required milestone sequence for MVP implementation.
  • Complete and verify one milestone before starting the next one.
  • Update the PLANS.md progress and execution log as milestones are completed.
  • Run milestones under the Sol coordinator and Luna worker/reviewer loop defined in PLANS.md and .codex/.
  • The coordinator must independently review Luna's changes and delegate explicit Luna repairs until verification passes or a genuine blocker remains.
  • Use the existing add-user.sh only as a behavioral reference.
  • New code must improve its safety rather than copy its weaknesses.

General priorities

  • Preserve a working WireGuard configuration above all else.
  • Prefer correctness and recoverability over cleverness.
  • Keep CLI behavior independent from the TUI.
  • Make every mutating operation explicit and auditable.
  • Keep secrets out of output, logs, tests, and error messages.
  • Minimize required dependencies.
  • Support operation over SSH and ordinary terminal emulators.
  • Write user-facing text in Russian unless the surrounding interface uses another language.
  • Keep identifiers, functions, CLI command names, and code comments in English.
  • Avoid unrelated refactors while implementing a focused change.

Bash baseline

  • Use Bash, not POSIX sh.
  • Start executable scripts with #!/usr/bin/env bash.
  • Enable set -Eeuo pipefail in production entry points.
  • Understand strict-mode exceptions before suppressing them.
  • Use if command; then when a nonzero status is expected.
  • Do not append || true unless the ignored failure is intentional and documented.
  • Set umask 077 before creating configs, keys, metadata, logs, or backups.
  • Require a supported Bash version at startup when using version-specific features.
  • Prefer Bash builtins over unnecessary subprocesses.
  • Use printf rather than echo -e.
  • Use [[ ... ]] for Bash conditionals.
  • Use (( ... )) for arithmetic conditions.
  • Use case for command dispatch and finite state handling.
  • Use local for function-local variables.
  • Declare variables close to first use.
  • Use readonly for constants after configuration is loaded.
  • Use uppercase names only for exported variables and true constants.
  • Use lowercase snake_case for local variables and functions.
  • Give functions verb-based names such as load_config or add_client.
  • Keep functions focused and normally below about 60 lines.
  • Return statuses from functions; print data only when output is the contract.
  • Do not mix machine-readable results with progress messages.
  • Send errors and diagnostics to stderr.
  • Use explicit exit codes for expected CLI failure categories.

Quoting and data handling

  • Double-quote parameter expansions unless splitting is deliberately required.
  • Use "${array[@]}" when forwarding array elements.
  • Use arrays to build commands; never construct commands as strings.
  • Never use eval.
  • Never pass user-controlled text to bash -c.
  • Avoid command substitution for multiline or NUL-sensitive data.
  • Use mapfile -t for line-oriented command output when appropriate.
  • Use IFS= read -r to read literal lines.
  • Use read -r -d '' or NUL delimiters for arbitrary file names.
  • Use -- before user-derived positional arguments where supported.
  • Do not rely on locale-sensitive parsing.
  • Set LC_ALL=C locally for command output that must be parsed predictably.
  • Do not parse human-formatted output when a stable dump format exists.
  • Prefer wg show <interface> dump for WireGuard state parsing.
  • Treat names, endpoints, addresses, paths, and config values as untrusted input.
  • Validate input with allowlists and semantic checks.
  • Reject control characters and embedded newlines in user input.
  • Never derive a filesystem path from an unchecked client name.
  • Canonicalize or constrain paths before reading or writing them.

Configuration

  • Keep server-specific values in wg-manager.conf.
  • Resolve the project directory from ${BASH_SOURCE[0]}.
  • Do not depend on the caller's current working directory.
  • Do not silently overwrite administrator configuration.
  • Validate every required setting at startup.
  • Reject unknown enum values such as unsupported tunnel modes.
  • Validate numeric ranges before arithmetic use.
  • Validate IPv4, IPv6, CIDR, port, and hostname values before use.
  • Do not source a configuration file that may be writable by untrusted users.
  • If sourcing is retained, require root ownership and non-group/world-writable permissions.
  • Prefer a restricted KEY=VALUE parser for long-term safety.
  • Environment overrides must be documented and narrowly scoped.
  • Never accept key material through command-line arguments.
  • Avoid exporting secrets into the process environment.

Temporary files and cleanup

  • Create temporary files with mktemp.
  • Create mutation staging files on the same filesystem as the target.
  • Never use predictable temporary filenames.
  • Register cleanup immediately after creating temporary resources.
  • Use a cleanup function with trap for EXIT, INT, and TERM.
  • Quote trap bodies safely; avoid premature expansion.
  • Preserve the original exit status during cleanup.
  • Do not remove a path unless this process created it or validated it exactly.
  • Apply restrictive permissions before writing secret content.
  • Do not leave key material in world-readable temporary directories.

WireGuard safety

  • Require root only for commands that need privileged access or mutation.
  • Allow safe read-only commands without root when system permissions permit it.
  • Check that the configured interface and config file agree.
  • Identify peers by public key, not only by display name.
  • Treat comments such as ### Client NAME as metadata, not identity.
  • Detect duplicate public keys and overlapping AllowedIPs.
  • Detect address collisions before generating any persistent file.
  • Distinguish managed peers from unmanaged peers.
  • Never modify an unmanaged peer implicitly.
  • Do not regenerate server keys automatically.
  • Do not rotate or replace client keys without explicit confirmation.
  • Never print private or preshared keys in routine output.
  • Never include key values in traces or debug logs.
  • Disable shell tracing around all secret-handling code.
  • Store client files with mode 0600.
  • Keep directories containing client material at mode 0700.

Mutating operations

  • Serialize mutations with flock.
  • Acquire the lock before re-reading mutable state.
  • Revalidate assumptions after the lock is acquired.
  • Create a backup before every persistent change.
  • Write the complete proposed config to a staging file.
  • Validate the staged config before replacing the live config.
  • Preserve the target owner, group, and restrictive mode.
  • Replace files atomically with a same-filesystem rename.
  • Apply the new configuration only after durable storage succeeds.
  • Verify active state after applying the change.
  • Roll back both disk and runtime state on failure.
  • Report rollback failure as a critical error.
  • Never append directly to the live WireGuard config.
  • Never use broad text deletion to remove a peer block.
  • Match an exact managed block and its public key.
  • Default to archiving client files instead of permanent deletion.
  • Require explicit confirmation before destructive or restorative actions.
  • Make repeated operations fail safely or behave idempotently.

Backups and audit log

  • Timestamp backups in an unambiguous UTC format.
  • Include the interface name in backup metadata or filenames.
  • Keep a bounded number of automatic backups.
  • Never prune the only known-good backup.
  • Validate a backup before offering restoration.
  • Back up the current state before restoring an older state.
  • Record who initiated a mutation when that information is available.
  • Log the operation, target, timestamp, outcome, and concise error.
  • Do not log private keys, preshared keys, or full client configs.
  • Avoid logging full environment dumps or command lines with secrets.
  • Make logs readable only by root by default.
  • Log failed mutations and rollback outcomes.

CLI design

  • TUI actions must call the same backend functions as CLI commands.
  • Keep CLI commands usable when gum is unavailable.
  • Provide help and useful usage errors.
  • Reject unknown commands and extra positional arguments.
  • Keep command names stable once documented.
  • Use stdout for requested data and stderr for warnings or progress.
  • Do not add decorative ANSI output when stdout is not a terminal.
  • Honor NO_COLOR for CLI colors where colors are used.
  • Return zero only when the requested operation succeeded.
  • Use distinct nonzero statuses for usage, validation, dependency, and runtime errors.
  • Avoid interactive prompts when a CLI command is explicitly noninteractive.
  • Require a confirmation flag for destructive noninteractive commands.
  • Never let localization change machine-parsed values or exit codes.

TUI with gum

  • Use gum as the only planned TUI framework.
  • Do not add dialog, whiptail, or a second TUI framework.
  • Do not download or install gum from the application.
  • Resolve gum in this order: WG_MANAGER_GUM, local bin/gum, then PATH.
  • Validate that the resolved path is executable.
  • Check required gum subcommands or minimum version at startup.
  • Fail with a clear message when TUI is requested without usable gum.
  • Keep all gum invocation details in small UI wrapper functions.
  • Backend functions must never call gum directly.
  • Use gum choose for short finite menus.
  • Use gum filter for searchable client selection.
  • Use gum input for short validated text fields.
  • Use gum confirm before deletion, restoration, or key rotation.
  • Use gum table only for display or selection, not as a data store.
  • Use gum pager for logs, diagnostics, and long text.
  • Use gum spin only when the wrapped operation can safely hide routine output.
  • Preserve stderr from failed commands behind a spinner.
  • Never show secret content inside a spinner command line.
  • Keep stable internal values separate from translated display labels.
  • Treat cancellation and Escape as normal control flow, not an error.
  • Return to the previous screen after cancellation.
  • Do not trap users in an endless menu loop after repeated failures.
  • Keep the main menu shallow and task-oriented.
  • Show interface name and current status on the main screen.
  • Use consistent verbs: view, add, remove, diagnose, restore, exit.
  • Show the exact target before asking for destructive confirmation.
  • Require stronger confirmation for restoring backups or deleting client material.
  • Keep colors readable on light and dark terminals.
  • Do not communicate status by color alone.
  • Keep layouts usable at 80 columns.
  • Avoid assumptions about mouse support.
  • Do not clear valuable terminal output after an error.
  • Detect noninteractive stdin or stdout before starting TUI.
  • Never emit TUI control output into pipelines or redirected files.

Error handling

  • Provide one concise user-facing error plus actionable context.
  • Preserve the failing command's status where meaningful.
  • Do not expose secret variable values in error messages.
  • Distinguish validation errors from system failures.
  • Distinguish skipped diagnostic checks from successful checks.
  • Diagnostic results use OK, WARN, FAIL, or SKIP.
  • A critical diagnostic failure must produce a nonzero status.
  • Include remediation guidance when it is reliable and specific.
  • Avoid guessing firewall fixes across distributions.
  • Continue independent diagnostic checks after a nonfatal failure.

Dependencies and portability

  • Assume a Linux server with Bash and WireGuard tools.
  • Keep required dependencies listed in MVP.md and README.
  • Treat qrencode, systemd, nft, and iptables as optional capabilities.
  • Detect optional commands before using them.
  • Do not fail the entire diagnostic run because one optional tool is absent.
  • Prefer feature detection over distribution detection.
  • Do not assume systemd is PID 1 on every supported server.
  • Support at least Linux x86_64; document additional tested architectures.
  • Do not assume the bundled gum binary matches the current architecture.
  • Report architecture mismatch clearly.

Tests

  • Add regression tests for every fixed bug.
  • Tests must not modify the host's real /etc/wireguard.
  • Use fixtures for server configs, peer blocks, and metadata.
  • Mock external commands through a controlled test PATH.
  • Cover wg, wg-quick, ip, systemctl, journalctl, nft, and iptables as needed.
  • Test success, expected failure, rollback, and interruption paths.
  • Test client names containing spaces, newlines, glob characters, and option prefixes.
  • Test duplicate keys, duplicate IPs, and overlapping networks.
  • Test empty peer lists and unmanaged peers.
  • Test CLI behavior without gum.
  • Test local binary, environment override, and PATH resolution for gum.
  • Test that logs do not contain generated secrets.
  • Test concurrent mutation attempts.
  • Test restoration failure and failed rollback reporting.
  • Keep tests deterministic; do not depend on external network access.
  • Use temporary test directories and remove them safely.

Quality gates

  • Run bash -n on every changed shell script.
  • Run ShellCheck on every changed shell script when available.
  • Run the relevant automated tests.
  • Format consistently; use shfmt when the project adopts a fixed style.
  • Do not silence ShellCheck globally to hide local problems.
  • Add a narrow inline suppression only with an explanatory comment.
  • Review diffs for accidental key material before finishing.
  • Review file permissions in tests that create secrets.
  • Verify that failure paths preserve the original config.
  • Verify CLI output with stdout redirected.
  • Verify TUI entry and cancellation in an interactive terminal.

Documentation

  • Update MVP.md only when product scope or architecture changes.
  • Keep operational usage in README once implementation begins.
  • Document every CLI command and its exit behavior.
  • Document required and optional dependencies separately.
  • Include examples that use placeholder keys and addresses only.
  • Never commit real endpoints, private keys, preshared keys, or client configs.
  • Explain backup and restore behavior before users rely on it.
  • Document limitations of handshake history and traffic visibility.

Definition of done

  • The requested behavior is implemented through shared backend functions.
  • Mutations are locked, validated, backed up, atomic, and reversible.
  • CLI operation remains available independently of the TUI.
  • TUI uses the configured gum resolution order.
  • Errors are actionable and do not reveal secrets.
  • Relevant tests pass.
  • bash -n passes.
  • ShellCheck has no unexplained findings.
  • Documentation matches observable behavior.
  • No unrelated files or user changes are overwritten.