Singularity
Guides

CLI Tools

Reference for all three Singularity CLI entry points -- services, tasks, and scripts -- with complete command listings, flags, and usage examples.

Singularity exposes three CLI tools, each registered as a console entry point in pyproject.toml. They are available after installation (uv sync) without needing to invoke Python directly.

# pyproject.toml
[project.scripts]
services = "cli.services:main"
tasks    = "cli.tasks:main"
scripts  = "cli.scripts:main"

Every command is built with Click and follows a consistent pattern: <tool> <command> [arguments] [options]. Running any tool without a subcommand prints its help text.

All CLI errors are displayed as Rich-formatted panels with color-coded titles, contextual details, and actionable hints that explain what went wrong and how to fix it.


Services CLI

Manage the full lifecycle of Singularity services -- discover, create, inspect, disable, delete, validate, and visualize dependencies.

singularity services list

List all discovered services with their endpoints and RPC status.

# Default compact listing
services list

# Detailed table with path, endpoint, type, and RPC status
services list --detailed

# Include disabled and core services
services list --all

# JSON output for programmatic consumption
services list --json

# Combine flags
services list --detailed --all

Options:

FlagShortDescription
--detailed-dShow path segments, endpoint, type (service/webhook), and RPC
--all-aInclude disabled and core (__base) services
--json-jOutput as JSON array

Example output (compact):

Found 5 active service(s):
  Name             | Endpoint               | RPC
  --------------------------------------------------
  users            | /api/v1/users          | Yes
  payments         | /api/v1/payments       | Yes
  stripe [wh]      | /api/v1/stripe         | No
  notifications    | /api/v1/notifications  | No
  analytics        | /api/v1/analytics      | No

services info

Show detailed information about a specific service including methods, HTTP exposed routes, RPC settings, and webhook events.

services info payments

Example output:

  Service: payments
  Path: services/v1/payments
  Module: services.v1.payments.service
  API Endpoint: /api/v1/payments
  Class: PaymentsService
  Status: Active

  Methods:
    - get      /api/v1/payments
    - post     /api/v1/payments

  HTTP Exposed:
    - POST     /api/v1/payments/refund  (post_refund)
    - GET      /api/v1/payments/status  (get_status)

  Attributes:
    rpc_exposed: True
    blacklist: ['public']

singularity generate service

Scaffold a new service with boilerplate code. Supports templates and mixins for common patterns.

# Basic CRUD service
singularity generate service users

# Nested path with description
singularity generate service v1/users -d "User management service"

# Minimal template with auth
singularity generate service v1/auth --template minimal --auth

# Webhook service with database access
singularity generate service v1/stripe --template webhook --db

# Service with RPC and custom methods
singularity generate service billing --rpc --methods get,post

# Service with WebSocket support
singularity generate service chat --websocket

# Overwrite existing service
singularity generate service users --overwrite

Arguments and Options:

ParameterDescription
SERVICE_NAMESimple name (users) or nested path (v1/users)
--description, -dService description
--template, -tBase template: crud (default), minimal, empty, webhook
--methods, -mComma-separated HTTP methods (overrides template default)
--rpcEnable RPC exposure (rpc_exposed = True)
--websocket, --wsAdd a WebSocket endpoint
--authAdd JWT authentication dependency
--dbAdd database session dependency
--overwrite, -iOverwrite existing service files

Templates:

TemplateMethodsAcquireDescription
crudGET, POST, PUT, DELETEYesFull CRUD operations with DB session
minimalGET, POSTYesLightweight service with basic operations
empty(none)NoBare skeleton for fully custom services
webhookPOST (via BaseWebhook)YesWebhook receiver with signature verification

services delete

Remove or disable a service. Requires either --soft or --hard.

# Soft delete -- disable without removing files
services delete old_service --soft

# Hard delete -- permanently remove files
services delete old_service --hard

# Skip confirmation prompt
services delete old_service --hard --force
FlagDescription
--softAdd to disabled list; manager skips it on startup. Files remain intact.
--hardPermanently delete the service directory from disk.
--force, -fSkip the confirmation prompt (hard delete only).

Hard delete is irreversible. The CLI lists all files that will be removed and asks for confirmation unless --force is used.


services enable

Re-enable a previously soft-deleted (disabled) service.

services enable old_service

After enabling, restart the server to load the service.


services validate

Validate a service name and preview what would be created, without writing any files.

services validate v1/analytics

# Preview with specific options
services validate v1/analytics --template crud --rpc --auth

Example output:

  Name: v1/analytics
  Class: AnalyticsService
  Directory: services/v1/analytics
  Service file: services/v1/analytics/service.py
  API Endpoint: /api/v1/analytics

  Configuration:
    Template: crud
    Methods: GET, POST, PUT, DELETE
    RPC: Yes
    Acquire: Yes
    WebSocket: No
    Auth: Yes

  Ready to create. Run:
    singularity generate service v1/analytics --template crud --rpc --auth

singularity services graph

Visualize the service dependency graph. Detects RPC descriptors, remote Microservice descriptors, and blacklist declarations.

# ASCII output in the terminal
services graph

# Include disabled and core services
services graph --all

# JSON output
services graph --json

# DOT format for Graphviz
services graph --dot

# Pipe to Graphviz to render as PNG
services graph --dot | dot -Tpng -o deps.png

Options:

FlagShortDescription
--json-jOutput as JSON with nodes, edges, remote_edges, and blocked arrays
--dotOutput as DOT (Graphviz) format for visualization
--all-aInclude disabled and core services

Example output (ASCII):

Service Dependencies:

  Local RPC:
    orders ──> payments
    orders ──> users

  Remote (cross-deployment):
    invoices ──> billing (https://billing.internal:8000)

  Blacklisted:
    payments x── public

  Isolated (no dependencies, not depended on):
    analytics
    notifications

services play

Interactive playground for testing a service with mocked dependencies. Instantiates the service using the testing harness (ServiceTestClient + TestAcquire) and drops into a REPL.

# Start a playground session
services play users

# Nested service path
services play v1/billing

Example session:

  Singularity Playground -- users (UsersService)
  Available methods: get, post, put, delete
  RPC dependencies: billing (auto-mocked)

  Commands: .help  .rpc  .ms  .calls  .quit

  > users> get()
    {"status": "ok", "users": []}

  > users> post(data={"name": "John"})
    {"status": "created", "data": {"name": "John"}}

  > users> .rpc billing get_balance {"balance": 100}
    OK: billing.get_balance -> {"balance": 100}

  > users> .calls
    RPC billing.get_balance({})

  > users> .quit

Dot commands:

CommandDescription
.helpShow available methods with signatures
.rpc <name> <method> <json>Set a mock RPC response
.ms <name> <method> <json>Set a mock Microservice response
.callsShow all recorded RPC/MS calls
.quitExit the playground

The playground auto-detects RPC and Microservice descriptors on the service class and creates empty mocks for each. You can override responses at any time with .rpc and .ms commands.


services stubs

Generate typed Python stub classes from all RPC-exposed services. The stubs provide IDE autocomplete for inter-service RPC calls.

# Generate to the default path
services stubs

# Generate to a custom path
services stubs --output ./my_stubs.py

Options:

FlagShortDefaultDescription
--output-osingularity/rpc/stubs.pyOutput file path

Example output:

"""
Auto-generated RPC stubs -- do not edit.
Run `services stubs` to regenerate.
"""
from typing import Any

class PaymentsRPC:
  """Stub for 'payments' service."""
  async def get(self) -> Any: ...
  async def post(self, data: dict) -> Any: ...
  async def get_status(self, payment_id: str) -> Any: ...

class UsersRPC:
  """Stub for 'users' service."""
  async def get(self) -> Any: ...
  async def post(self, data: dict) -> Any: ...

Stubs are generated via introspection -- they reflect the actual method signatures of your services. Regenerate after adding or modifying RPC-exposed service methods.


services dashboard

Open a live terminal dashboard (TUI) for browsing services, dependencies, hooks, and lifecycle info. Built with Textual and requires the optional dashboard extra.

# Install the dashboard extra
uv sync --extra dashboard

# Launch the dashboard
services dashboard

Layout:

┌─────────────────────────────────────────────────────────┐
│  Singularity Dashboard              [q] quit  [?] help  │
├────────────────────────┬────────────────────────────────┤
│  Services        (5)   │  Service Detail                │
│  ─────────────────     │  ─────────────────────────     │
│  ● users     [RPC]     │  Name: users                   │
│  ● payments  [RPC]     │  Endpoint: /api/v1/users       │
│  ● orders              │  Methods: GET POST PUT DELETE   │
│  ○ analytics [disabled]│  RPC: Yes                      │
│  ◆ stripe    [webhook] │  Hooks: before(all), after(all)│
├────────────────────────┴────────────────────────────────┤
│  Dependency Graph                                       │
│  users ──▸ payments     orders ──▸ payments             │
├─────────────────────────────────────────────────────────┤
│  Logs                                                   │
│  12:03:01 INFO  Discovered 5 service(s)                 │
│  12:03:01 INFO  Dependency graph rendered               │
└─────────────────────────────────────────────────────────┘

Keybindings:

KeyAction
/ Navigate service list
EnterSelect service (updates detail panel)
rRefresh service discovery
gToggle dependency graph panel
lToggle log panel
?Show keyboard shortcuts
qQuit

The dashboard is read-only -- it uses ServiceDiscovery introspection and does not require a running server. Service status indicators: ● active, ○ disabled, ◆ webhook.

Tasks CLI

Manage, inspect, run, and serve background tasks powered by Celery and Redis.

singularity tasks list

List all discovered background tasks with their descriptions and parameter counts.

tasks list

Example output:

Found 3 tasks:
----------------------------------------------------------------------
Name                      | Description                    | Params
----------------------------------------------------------------------
send_email                | Send a transactional email     | 3
process_order             | Process an e-commerce order    | 3
generate_report           | Generate a PDF report          | 2

Use 'tasks info <task_name>' for parameter details.

tasks info

Show detailed information about a specific task, including its full parameter signature, types, defaults, and configuration.

tasks info send_email

Example output:

Task: send_email
    Send a transactional email

    Parameters:
    --------------------------------------------------
    Name            Type       Required   Default
    --------------------------------------------------
    to              str        Y          -
    subject         str        Y          -
    body            str        Y          -

    Config:
      Notifications: log, callback
      Max Retries: 3 | Retry Delay: 60s | Time Limit: 3600s

singularity generate task

Generate a new task file with boilerplate in tasks/executable/.

# Create a task with a description
singularity generate task send_notification -d "Send push notifications to users"

# Overwrite an existing task
singularity generate task send_notification -d "Updated notification logic" --overwrite
OptionShortDescription
--description-dTask description
--overwrite-iOverwrite existing task file

The generated file includes the @task decorator, a stub function with a placeholder parameter, and an @on_complete callback.


tasks run

Trigger a task manually from the command line.

# Run with keyword arguments (JSON)
tasks run send_email -k '{"to": "test@example.com", "subject": "Hello", "body": "World"}'

# Run with a countdown delay (task starts in 60 seconds)
tasks run process_order -k '{"order_id": "ord_123", "items": []}' -c 60

# Positional arguments
tasks run send_email test@example.com "Hello" "World"
OptionShortDescription
--kwargs-kJSON dictionary of keyword arguments
--countdown-cDelay in seconds before the task starts

The --kwargs flag accepts both JSON strings and Python dict literals (parsed via ast.literal_eval as a fallback).


tasks result

Check the status and result of a previously submitted task.

tasks result abc12345-task-id

Example output:

Task ID: abc12345-task-id
State: SUCCESS
Result: {'status': 'sent', 'to': 'test@example.com'}

States: PENDING, STARTED, SUCCESS, FAILURE, REVOKED.


singularity tasks worker

Start a Celery worker instance to consume and execute tasks.

# Default worker (2 threads)
tasks worker

# High-concurrency worker with gevent pool
tasks worker --concurrency 8 --pool gevent

# Worker with Beat scheduler for periodic tasks
tasks worker --beat

# Debug-level logging
tasks worker --loglevel debug

# Autoscaling between 2 and 10 workers
tasks worker --autoscale 10,2

# Consume from specific queues
tasks worker --queues celery,priority
OptionTypeDefaultDescription
--concurrencyint2Number of concurrent workers
--loglevelchoiceinfodebug, info, warning, error, critical
--queuesstrceleryComma-separated queue names
--hostnamestrautoCustom worker hostname
--max-tasks-per-childint1000Replace child after N tasks
--prefetch-multiplierint1Messages to prefetch per worker
--poolchoicethreadsprefork, eventlet, gevent, threads, solo
--autoscalestr--Autoscale range as max,min
--beatflag--Enable Celery Beat scheduler

When using --pool gevent, the CLI automatically applies gevent monkey patching before any other imports. This is handled transparently -- you do not need to patch manually.

Scripts CLI

Manage database migration scripts, data patches, and maintenance operations.

scripts list

List all discovered executable scripts with their auto-run status, rerun flag, deprecation state, affected tables, and descriptions.

# Detailed listing (default)
scripts list

# Simplified listing
scripts list --simple

Example output (detailed):

Available Scripts (4 found)
=================================================================================
ID   Script Name                    Auto-run   Rerun    Deprecated   Affected Tables
----------------------------------------------------------------------------------
1    cleanup_orphaned_records       ON         OFF      No           temp_uploads
2    create_stripe_products         ON         OFF      No           products, prices
3    old_migration_v1               OFF        OFF      Yes          (none)
4    seed_initial_data              ON         ON       No           users, roles

singularity generate script

Generate a new script file with proper BaseScript boilerplate.

# Create with a description
singularity generate script add_user_roles -d "Add default user roles to the database"

# Overwrite an existing script
singularity generate script add_user_roles -d "Updated roles" --overwrite
OptionShortDescription
--description-dScript description
--overwrite-iOverwrite existing script file

The generated file includes:

  • BaseScript inheritance with constructor
  • execute(), rollback(), and verify() method stubs
  • Path setup for imports
  • CLI entry point (run_cli())

scripts run

Execute a script by name or numeric ID. Supports run (default), rollback, and status subcommands.

# Run a script (default action)
scripts run add_user_roles

# Force rerun even if already succeeded
scripts run add_user_roles run --force

# Check execution status
scripts run add_user_roles status

# Roll back a previously executed script
scripts run add_user_roles rollback

# Run by numeric ID
scripts run 2

# Check status by ID
scripts run 2 status
ArgumentDescription
IDENTIFIERScript name or numeric ID from the list
COMMANDrun (default), rollback, or status

scripts history

Display the full execution history from the script_run_tracker database table. Shows status, timestamps, hash changes, and error messages.

scripts history

Example output:

Executed Scripts History (3 total)
============================================================
Script Name                         Status       Executed At          Modified   Hash
------------------------------------------------------------
create_stripe_products              SUCCESS      2024-06-15 10:23:01  Current    a1b2c3d4e5f6...
cleanup_orphaned_records            SUCCESS      2024-06-15 10:23:02  CHANGED    f6e5d4c3b2a1...
old_migration_v1                    ROLLED_BACK  2024-06-14 08:15:30  Missing    (none)

Status indicators:

  • Success -- Script completed and verified
  • Failed -- Script threw an exception (error message shown below)
  • Pending -- Script started but has not finished
  • Rolled back -- Script was rolled back via CLI

scripts sync-hashes

Populate missing content_hash values for scripts that were executed before hash tracking was introduced. This updates the database with current file hashes so that future change detection works correctly.

scripts sync-hashes

scripts startup

Run all auto-run scripts, simulating the application startup behavior. Uses PostgreSQL advisory locks for multi-worker coordination.

scripts startup

Command Summary

CommandDescription
scripts listList all discovered scripts with metadata
scripts list --simpleCompact listing without details
singularity generate script <name> -d "desc"Generate a new script with boilerplate
scripts run <name|id>Execute a script
scripts run <name|id> rollbackRoll back a script
scripts run <name|id> statusCheck script execution status
scripts historyShow full execution history from the database
scripts sync-hashesBackfill missing content hashes
scripts startupRun all auto-run scripts

Entry Points

All three CLIs are registered as console scripts in pyproject.toml:

[project.scripts]
scripts  = "cli.scripts:main"
tasks    = "cli.tasks:main"
services = "cli.services:main"

After running uv sync, these commands are available directly in your shell without a python -m prefix. The src directory is included in pythonpath via the hatch build configuration, so all internal imports (e.g., services.__base.discovery, tasks.core.runner) resolve correctly.

If you are running commands outside of the installed package (e.g., during development), use singularity services list to ensure the correct Python path and virtual environment are used.