Skip to content

CLI commands

dotnet run --project src/StayFn.Cli -- <command> in the repository, or the installed tool stayfn anywhere else: dotnet tool install -g stayfn --add-source https://nuget.pkg.github.com/rizanc/index.json (GitHub Packages, a token with read:packages). The tool carries the host, the reference functions and the OHIP spec snapshot, so dev, mcp stdio, new … (including --operation), catalog export and ohip ping need no repository. Exit codes are stated per command; --help works on every level.

Command What it does Exit codes
new function <name> [--area] [--description] [--input name:type[?]]… [--output …]… [--operation] [--dir/--tests-dir/--docs-dir] [--namespace] [--overwrite] [--root] [--specs] Scaffolds an [OhipFunction] from the templates the MCP function.scaffold tool uses: the class, its WireMock tests and a catalog doc stub, confined to --root (default: the repository root). ? marks an optional member, [] a list (quote it in zsh). One to three non-list inputs without --operation give a plain signature (Run(DateOnly date, string? roomType, IFunctionContext ctx)); more inputs, a list or an operation give an input record. 0 written, 1 refused (name, type, operation, existing file, path), 2 usage
new project <name> [--dir <path>] [--feed <url|folder>] [--sdk-version <version>] A ready tenant repository in --dir (default ./<name>, must be empty): <name>.sln, functions/<name>.Functions.csproj on StayFn.Abstractions, StayFn.Events and StayFn.Analyzers (private), tests/<name>.Functions.Tests.csproj on xunit, FluentAssertions and StayFn.Testing, all at StayFnVersion in Directory.Build.props (default: the tool’s own version); the sample custom/ping with its test (the shared templates); docker-compose.yml with the host’s docker/postgres/init.sql; .env.example; .mcp.json (stayfn mcp stdio --root .); nuget.config with GitHub Packages for StayFn.* (credentials from STAYFN_FEED_USERNAME/STAYFN_FEED_TOKEN, never a token) and nuget.org for the rest, or --feed instead without credentials; global.json, .gitignore, .vscode/settings.json, README.md. Later new function calls default to functions/ and tests/ with the project’s namespace. 0 written, 1 refused (directory not empty), 2 usage (name, version)
new handler <name> --event <event> … The same for an [EventHandler] method. as above
new scheduled <name> --schedule "<6-field cron>" … The same for a scheduled function. as above
catalog export [--format json|markdown] [--operations] [--assemblies <dll>…] [--out <file>] The registry’s catalog (reference set + given assemblies, OHIP operation rows on request) as sorted, timestamp-free JSON or a markdown overview per area. 0, 2 bad format/assembly
sdk generate --lang csharp|typescript [--area <area>]… [--out <dir>] [--from <url> [--api-key <key>] | --assemblies <dll>…] [--namespace <ns>] [--client-name <name>] [--package-name <name>] A typed caller SDK from a running host’s catalog (--from: GET /api/catalog, then each exposed function’s descriptor, with a key carrying functions:read, from --api-key or STAYFN_API_KEY, never printed) or offline from the reference set plus --assemblies. Only TenantApi/Public functions. csharp writes Models.g.cs, <client-name>.g.cs and README.md (default ./StayFn.Sdk, namespace StayFn.Sdk, client StayFnClient) over the StayFn.Client package; typescript writes index.js, index.d.ts, package.json and README.md for Node 18+ with no dependencies (default ./stayfn-client). Output is deterministic; regenerate instead of editing. 0 written, 1 host refused (401/403 …) or unreachable, 2 usage (language, URL, --from with --assemblies, no function in the areas, bad assembly)
replay --dead-letter <id> [--tenant <id>] [--base-url <url>] [--token <jwt>] POST /api/admin/dead-letters/{id}/replay — the dashboard’s atomic, audited, once-only replay. Token from --token or STAYFN_ADMIN_TOKEN, host from --base-url or STAYFN_BASE_URL (default http://localhost:5080). 0 enqueued, 1 refused (already replayed, not found, not possible), 2 no token / unreachable
equivalence run [--list] [--case <name>] [--compare values|presence] [--out <file>] [--ohip-env <env> --hotel <code> --confirmation <n>] The OPERA 5 vs OHIP equivalence harness; --list shows the cases; a --case that matches nothing is an error. 0 no diffs, 1 diffs/errors, 2 configuration
ohip ping --env <env> --hotel <code> Token + one read-only hotel call through the StayFn pipeline (OHIP_<ENV>_* variables / .env). 0 ok, non-zero on failure
ohip stream-probe --env <env> [--seconds N] [--offset-type highest | --offset N] [--max-events N] [--sessions N --resume next|same] [--ping-seconds N] [--corrupt-token] [--no-key-hash] [--subprotocol …] [--upgrade-headers] Streaming API diagnostic: one connection at a time, connection_init, newEvent subscription; prints structure only (message types, timings, close codes, moduleName|eventName, element names, shapes, hashed ids) — never tokens, keys, codes, hosts or values. Reads OHIP_<ENV>_CHAIN_CODE, _HOTEL_ID, optional _WEBSOCKET_URL. Respect OHIP’s streaming rules: one consumer per chain and app key, ≥ 10 s between sessions (the probe waits --gap-seconds, min 10). 0 acknowledged, 1 configuration, 2 credentials refused (4401/4403), 3 upstream
dev seed --env <env> --tenant "<name>", dev token --role owner|operator|viewer [--tenant] Development tenant seeding and HS256 admin tokens (ASPNETCORE_ENVIRONMENT=Development only).
mcp stdio [--assemblies] [--specs] [--root] The local MCP server for Claude Code (docs/authoring-with-claude-code.md). --specs defaults to <repo>/tools/ohip-specs/26.3.0.0, else the snapshot shipped with the tool.