Skip to content

Repository files navigation

Server Scripts CLI (ssc)

Release License: MIT Bash 4.0+ YAML Config CI Last Commit

One CLI over a directory of shell and Python scripts, driven by a YAML manifest.

A server accumulates scripts faster than anyone documents them. ssc reads YAML front-matter out of the scripts themselves, writes a manifest.yaml from it, and gives you one command to list, run, inspect and monitor what is there.

About

  • Repository: server-scripts-cli
  • Command: ssc (short for Server Scripts CLI)
  • Binary: ssc.sh in the repository, installed as ssc

This documentation uses ssc throughout for brevity.

Features

  • Manifest from front-matter: generate-manifest.sh reads a # --- YAML block from the head of each .sh and .py file and writes manifest.yaml
  • Four type tiers: Interactive, One-time, Background and Internal, listed in full under ssc list --help
  • Interactive types by default: ssc list shows the five Tier 1 types (report, admin, diagnostic, check, orchestrator); --all shows the rest
  • One interface: list, run, info, status, logs, validate, generate
  • systemd queries: ssc status reads systemctl, ssc logs reads journalctl for the service named in a script's front-matter
  • Filters: category, type, status, a name search, a limit, and full paths
  • Bash and yq only: no Python or Node runtime, no package manager, no daemon

What it is not

  • Not a scheduler. ssc runs a script when you ask it to. Recurring execution stays with cron or a systemd timer; deployment: scheduled in the front-matter records that fact, it does not create the timer.
  • Not a sandbox. ssc run execs the script with your own permissions. The only gate is the script-name regex ^[a-zA-Z0-9._-]+$ (validate_script_name in ssc.sh) plus a confirmation prompt for requires_root: true. Treat every script in the manifest as code you have read. See SECURITY.md.
  • Not remote. Everything happens on the machine you run it on. There is no agent, no inventory, no push.
  • status and logs need systemd. They work on a Linux host with systemctl and journalctl. The other commands are portable Bash 4 and run on macOS too, but on macOS those two have nothing to query.

Screenshot

ssc list showing 65 interactive scripts of 150 in the manifest

ssc list on the maintainer's own server when the screenshot was taken, with 150 scripts in the manifest, 65 of them carrying a Tier 1 type and therefore shown by default. That tree has kept growing since, so read the two numbers as a shape, not as a current count. A fresh clone of this repository has the four demo scripts instead and shows three of them, since deploy-example is Tier 2.

Quick Start

git clone https://github.com/fidpa/server-scripts-cli
cd server-scripts-cli

# Read front-matter and write manifest.yaml
./generate-manifest.sh

# List the demo scripts, run one, inspect another
./ssc.sh list
./ssc.sh run backup-example
./ssc.sh info monitoring-example

generate-manifest.sh scans exactly one directory: scripts/ if it exists, and examples/demo-scripts/ otherwise. The first match wins, so once you add a scripts/ tree the demo scripts drop out of the manifest. The scan is recursive and skips .venv/, venv/, node_modules/, __pycache__/ and __init__.py. A script's category is the first directory below scripts/, which is why the demo scripts come out with an empty category.

Installation

Automated

# One-liner, adds an alias to ~/.bashrc
curl -sSL https://raw.githubusercontent.com/fidpa/server-scripts-cli/main/install.sh | bash

./install.sh --local   # alias in ~/.bashrc (default)
./install.sh --user    # symlink to ~/.local/bin
./install.sh --system  # copy to /usr/local/bin (requires sudo)

Piping a script from the network into a shell means trusting the source. Clone first and read install.sh if you would rather not.

Manual

Click to expand manual options

Option 1: Local repository (alias)

git clone https://github.com/fidpa/server-scripts-cli ~/server-scripts-cli
cd ~/server-scripts-cli
./generate-manifest.sh

echo "alias ssc='~/server-scripts-cli/ssc.sh'" >> ~/.bashrc
source ~/.bashrc

Option 2: System-wide (copy binary)

sudo cp ssc.sh /usr/local/bin/ssc
sudo cp generate-manifest.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/{ssc,generate-manifest.sh}

Option 3: User-local (symlink)

mkdir -p ~/.local/bin
ln -s $(pwd)/ssc.sh ~/.local/bin/ssc

All three end up with the command named ssc. ssc looks for manifest.yaml in the repository root it resolves through git rev-parse --show-toplevel, falling back to the directory of the resolved script path, so a symlink keeps working while a copied binary needs its own manifest next to it, or SSC_MANIFEST_FILE pointing at one.

Commands

Command Purpose
ssc list List scripts with filters (Tier 1 types by default)
ssc list --all Include One-time, Background and Internal types
ssc run <name> [args...] Execute a script, passing further arguments through
ssc info <name> Show a script's manifest entry
ssc status Query systemd service state, timers and recent logs
ssc logs <name> Show journalctl output for the script's service
ssc validate Check YAML syntax and that every path in the manifest exists
ssc generate Regenerate the manifest from front-matter

CLI Reference

Output of ssc --help, verbatim except for the closing MANIFEST: line, which prints the absolute path of the manifest ssc resolved for you:

ssc - Server Scripts CLI v1.4.0

USAGE:
    ssc <command> [options]

COMMANDS:
    list        List all scripts in manifest
    run         Execute a script by name
    info        Show detailed script information
    status      Show systemd service status
    logs        Show service logs (journalctl)
    validate    Validate manifest integrity
    generate    Regenerate manifest from front-matter
    help        Show this help message

LIST OPTIONS:
    -c, --category <name>   Filter by category (production, operations, etc.)
    -s, --status <status>   Filter by status (active, deprecated, unknown)
    -t, --type <type>       Filter by type (admin, report, diagnostic, library, helper, daemon)
    -p, --paths             Show full paths
    -n, --limit <num>       Limit output
    --search <term>         Search by name

RUN OPTIONS:
    -f, --force             Force run even if deprecated

STATUS OPTIONS:
    -s, --script <name>     Status for specific script
    -t, --timers            Show timer overview
    -l, --logs              Include recent logs
    -n, --lines <num>       Number of log lines

EXAMPLES:
    ssc list --status active
    ssc list --category operations --type backup
    ssc run backup-example --help
    ssc info monitoring-example
    ssc status --timers
    ssc logs health-check -n 50

ENVIRONMENT:
    SSC_MANIFEST_FILE       Manifest to read (default: manifest.yaml in the repo root)
    SSC_REPO_ROOT           Directory that script paths resolve against
    SSC_LOG_LEVEL           debug, info (default), warning, error
    SSC_COLOR               auto (default), always, never
    SSC_SYSTEMD_ENABLED     false makes status and logs skip systemd
    SSC_EXEC_TIMEOUT        Seconds before run kills the script (0 = off)
    SSC_STRICT_VALIDATION   true checks every manifest field against the schema

    Also read from ~/.config/ssc/ssc.env; see config/ssc.env.example

The top-level help omits one option that ssc list accepts: -a, --all. It is listed by ssc list --help, which also prints the full type tiers.

YAML Front-Matter Schema

Add a # --- block to the head of a script; generate-manifest.sh reads the first 30 lines of each file looking for it:

#!/bin/bash
# ---
# deployment: manual
# service: backup.service
# status: active
# type: admin
# requires_root: true
# ---
#
# Your script here

All five fields plus the derived path and category end up in manifest.yaml. See docs/MANIFEST_SCHEMA.md for the value sets.

Requirements

  • Bash: 4.0+ (ssc.sh uses ${var,,} case conversion, which Bash 3 rejects)
  • yq: mikefarah/yq v4+. ssc feature-tests it with yq eval '.' /dev/null and refuses the Python yq wrapper, which has no eval subcommand
  • systemd: only for ssc status and ssc logs

Configuration

ssc needs none: every variable below has a default that matches what it does when you set nothing.

Variable Default Description
SSC_MANIFEST_FILE manifest.yaml in the repository root Read the manifest from somewhere else
SSC_REPO_ROOT git rev-parse --show-toplevel, else the directory of ssc.sh Directory that script paths are resolved against
SSC_LOG_LEVEL info debug, info, warning, error
SSC_COLOR auto auto (color when stdout is a terminal), always, never
SSC_SYSTEMD_ENABLED true false makes status and logs return without calling systemd
SSC_EXEC_TIMEOUT 0 Seconds before ssc run kills the script; 0 disables it
SSC_STRICT_VALIDATION false true checks every manifest field against the schema

The log level filters the status messages of ssc itself. What list, info and status print is data and goes out at every level, so SSC_LOG_LEVEL=error gives you the table without the commentary around it. debug prints the resolved repository root, the resolved manifest and the exact command behind ssc run to stderr.

Set them in your shell, or copy config/ssc.env.example to ~/.config/ssc/ssc.env, which ssc sources at startup. A variable set in the environment wins over the file. Sourcing executes the file, so ssc skips it and says so when it is not owned by you or when group or others can write it - chmod 600 it.

Documentation

Examples

examples/demo-scripts/ holds four runnable scripts, and they are what a fresh clone puts into the manifest:

  • backup-example.sh - scheduled backup, requires_root: true
  • monitoring-example.sh - collects system metrics
  • health-check.sh - service health validation, tied to health-check.service
  • deploy-example.sh - deployment automation, Tier 2, so --all to see it

Contributing

Issues and pull requests are welcome. CONTRIBUTING.md has the workflow, CODE_OF_CONDUCT.md the ground rules, and SECURITY.md the address for anything that should not be a public issue.

License

MIT License - Copyright (c) 2025-2026 Marc Allgeier (fidpa)

See LICENSE for details.

Author

Marc Allgeier (@fidpa)

About

YAML-based script management CLI: discovery, execution, and status tracking for large script repositories. Tab completion, category filtering, and systemd integration.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages