feat: add instruct command with platform reference for humans and agents
Adds `shsf instruct` as a first-stop command covering what SHSF is, a CLI command group overview, quick-start steps for humans, and the full AIDOC function authoring reference for AI agents. The program description and help footer now prompt users to run `shsf instruct` before anything else. Bumps version to 2.3.3. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "shsf-cli",
|
||||
"version": "2.3.2",
|
||||
"version": "2.3.3",
|
||||
"description": "Production-ready command-line interface and agent bridge for SHSF.",
|
||||
"type": "module",
|
||||
"files": [
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
import chalk from "chalk";
|
||||
|
||||
const AIDOC = `
|
||||
## SHSF Platform Reference — read this carefully before writing any code
|
||||
|
||||
---
|
||||
|
||||
### 1. Entry-point conventions
|
||||
|
||||
Every function MUST expose a single entry-point that the SHSF runtime calls.
|
||||
|
||||
**Python** (file extension: .py)
|
||||
\`\`\`python
|
||||
def main(args):
|
||||
# args is a dict injected by the runtime (see §2)
|
||||
return {"hello": "world"} # plain dict → 200 JSON response
|
||||
\`\`\`
|
||||
|
||||
**Go** (file extension: .go, package must be \`main\`)
|
||||
\`\`\`go
|
||||
package main
|
||||
|
||||
func main_user(args interface{}) (interface{}, error) {
|
||||
return map[string]string{"hello": "world"}, nil
|
||||
}
|
||||
\`\`\`
|
||||
• Go functions MUST use \`main_user\`, NOT \`main\`, as the user entry-point.
|
||||
• Dependencies go in a \`go.mod\` file (auto-downloaded by the runtime).
|
||||
• Supported Go versions: 1.20 / 1.21 / 1.22 / 1.23
|
||||
|
||||
**.NET / C#** (project-based runtime)
|
||||
\`\`\`csharp
|
||||
using SHSF;
|
||||
|
||||
var args = Runtime.LoadPayloadJson<Dictionary<string, JsonElement?>>();
|
||||
Runtime.Return(new { hello = "world" });
|
||||
\`\`\`
|
||||
• .NET functions are project-based: include a runnable \`.csproj\` and C# source files.
|
||||
• Do NOT use \`func.startup_file\` for .NET. The startup file should be an empty string.
|
||||
• Your code can use \`Runtime.LoadPayload()\`, \`Runtime.LoadPayloadJson<T>()\`, and \`Runtime.Return(object)\` from the auto-provisioned \`SHSF.Runtime.cs\` helper.
|
||||
• Supported .NET SDK images: 8.0 / 9.0 / 10.0
|
||||
|
||||
---
|
||||
|
||||
### 2. The \`args\` object
|
||||
|
||||
The runtime injects these fields. Always use .get() / nil-checks — never assume a field is present.
|
||||
|
||||
| Field | Type | Description |
|
||||
|------------|---------------|--------------------------------------------------------------|
|
||||
| body | string | Raw JSON string of the HTTP POST body — MUST be parsed with json.loads() before use |
|
||||
| queries | dict / map | URL query parameters (?key=value) |
|
||||
| route | string | Sub-path after the function URL (no leading slash). Default: "default" |
|
||||
| headers | dict / map | Incoming HTTP request headers (lowercased keys) |
|
||||
| raw_body | bytes/string | Raw request body bytes (for file uploads, binary data) |
|
||||
| method | string | HTTP method (GET, POST, PUT, PATCH, DELETE, QUERY, …) |
|
||||
|
||||
> ⚠️ \`body\` is a raw JSON string — you MUST call \`json.loads(body)\` before accessing fields.
|
||||
|
||||
Python example:
|
||||
\`\`\`python
|
||||
import json
|
||||
|
||||
def main(args):
|
||||
body = args.get("body", "{}")
|
||||
body = json.loads(body) # ← required: parse the JSON string first
|
||||
queries = args.get("queries", {})
|
||||
route = args.get("route", "default")
|
||||
name = body.get("name", "stranger")
|
||||
page = queries.get("page", "1")
|
||||
return {"greeting": f"Hello {name}", "page": page, "route": route}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
### 3. Custom responses (SHSF v2 protocol)
|
||||
|
||||
Return a plain dict/map for a simple 200 JSON response.
|
||||
Return the v2 envelope to control status code, headers, and body:
|
||||
|
||||
\`\`\`python
|
||||
def main(args):
|
||||
return {
|
||||
"_shsf": "v2",
|
||||
"_code": 201,
|
||||
"_headers": {"X-My-Header": "value", "Content-Type": "application/json"},
|
||||
"_res": {"created": True, "id": 42}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
v2 envelope fields:
|
||||
- _shsf (required): must be "v2"
|
||||
- _code (int): HTTP status code to return
|
||||
- _res (any): response body (string, dict, …)
|
||||
- _headers (dict): extra response headers to send
|
||||
- _location (string): redirect URL — only valid when _code is 301 or 302
|
||||
|
||||
---
|
||||
|
||||
### 4. Redirects
|
||||
|
||||
Set _code to 301 (permanent) or 302 (temporary) AND supply _location:
|
||||
|
||||
\`\`\`python
|
||||
def main(args):
|
||||
return {"_shsf": "v2", "_code": 302, "_location": "https://example.com/target"}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
### 5. Environment variables
|
||||
|
||||
Define them in the SHSF dashboard — NEVER hard-code secrets in source files.
|
||||
|
||||
\`\`\`python
|
||||
import os
|
||||
|
||||
def main(args):
|
||||
api_key = os.getenv("MY_API_KEY", "")
|
||||
if not api_key:
|
||||
return {"_shsf": "v2", "_code": 500, "_res": {"error": "MY_API_KEY not set"}}
|
||||
return {"ok": True}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
### 6. Persistent storage
|
||||
|
||||
- /app/ — files persist between invocations. Use for cached data, state files, etc.
|
||||
- /tmp/ — ephemeral; wiped between container restarts.
|
||||
|
||||
---
|
||||
|
||||
### 7. SHSF Database Communication (_db_com) — Python
|
||||
|
||||
\`\`\`python
|
||||
from _db_com import database
|
||||
|
||||
db = database()
|
||||
|
||||
def main(args):
|
||||
db.create_storage("my_app", purpose="application data")
|
||||
db.set("my_app", "username", "alice")
|
||||
username = db.get("my_app", "username")
|
||||
items = db.list_items("my_app")
|
||||
db.delete_item("my_app", "username")
|
||||
return {"username": username, "items": items}
|
||||
\`\`\`
|
||||
|
||||
Go dbcom equivalent:
|
||||
\`\`\`go
|
||||
package main
|
||||
|
||||
import "myfunction/dbcom"
|
||||
|
||||
func main_user(args interface{}) (interface{}, error) {
|
||||
db := dbcom.New()
|
||||
if _, err := db.Set("my-storage", "key", "value", nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value, err := db.Get("my-storage", "key")
|
||||
if err != nil { return nil, err }
|
||||
return map[string]interface{}{"value": value}, nil
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
### 8. Routing
|
||||
|
||||
args["route"] contains the URL sub-path after the function base URL (no leading slash).
|
||||
Default when no sub-path is given: "default".
|
||||
|
||||
\`\`\`python
|
||||
def main(args):
|
||||
route = args.get("route", "default")
|
||||
if route == "register":
|
||||
return handle_register(args)
|
||||
elif route == "login":
|
||||
return handle_login(args)
|
||||
else:
|
||||
return {"_shsf": "v2", "_code": 404, "_res": {"error": "route not found"}}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
### 9. Serving HTML
|
||||
|
||||
\`\`\`python
|
||||
def main(args):
|
||||
with open("index.html", "r") as f:
|
||||
html = f.read()
|
||||
return {"_shsf": "v2", "_code": 200, "_headers": {"Content-Type": "text/html"}, "_res": html}
|
||||
\`\`\`
|
||||
|
||||
For a fully static page: one .html file as the startup file, zero other files — SHSF serves it directly.
|
||||
|
||||
---
|
||||
|
||||
### 10. Raw body / file uploads
|
||||
|
||||
\`\`\`python
|
||||
def main(args):
|
||||
raw = args.get("raw_body")
|
||||
if raw is None:
|
||||
return {"_shsf": "v2", "_code": 400, "_res": {"error": "no body provided"}}
|
||||
if isinstance(raw, str):
|
||||
raw = raw.encode("latin-1")
|
||||
with open("/app/upload.bin", "wb") as f:
|
||||
f.write(raw)
|
||||
return {"_shsf": "v2", "_code": 200, "_res": {"saved": True}}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
|
||||
### 11. Secure headers (x-secure-header)
|
||||
|
||||
When a function has secure-header enabled, SHSF validates the x-secure-header before
|
||||
invoking — you do NOT need to re-validate it in your code.
|
||||
|
||||
---
|
||||
|
||||
### 12. Dependency files
|
||||
|
||||
| Runtime | File | How it works |
|
||||
|---------|-----------------|-------------------------------------------|
|
||||
| Python | requirements.txt | pip-installed before first run |
|
||||
| Go | go.mod + go.sum | module dependencies, auto-downloaded |
|
||||
| .NET | .csproj | NuGet restore/build handled by dotnet CLI |
|
||||
|
||||
---
|
||||
|
||||
### 13. Absolute rules — violations will cause the function to fail
|
||||
|
||||
- When the image is set to python, don't create go files, and vice versa.
|
||||
- Only create files allowed by the runtime file policy.
|
||||
- If no packages are needed, don't create a requirements.txt or go.mod file.
|
||||
- FORBIDDEN filenames: _runner.py, _runner.js, init.sh (reserved by the SHSF runtime)
|
||||
- Filenames must NEVER contain / or \\ (no subdirectories)
|
||||
- Never write partial files or placeholder comments like "# ... rest of code"
|
||||
- Never hard-code secrets — always use environment variables (§5)
|
||||
- Go entry-point is main_user(), never main()
|
||||
- .NET functions must include a runnable .csproj and return results via Runtime.Return(...)
|
||||
- Never invent SHSF-specific APIs that are not documented in this reference
|
||||
- Always \`import json\` and call \`json.loads(args.get("body", "{}"))\` in Python before accessing body fields
|
||||
`;
|
||||
|
||||
const CLI_OVERVIEW = `
|
||||
SHSF CLI — Command Overview
|
||||
════════════════════════════════════════════════════════
|
||||
|
||||
Command groups:
|
||||
|
||||
api Raw REST access (api request, api openapi)
|
||||
mcp MCP tools access (mcp init, mcp tools, mcp call, mcp docs)
|
||||
create Create resources (function, namespace, trigger)
|
||||
update Update resources (function, namespace, trigger)
|
||||
delete Delete resources (function, namespace, trigger)
|
||||
get Fetch details (function, namespace, trigger, exec-url)
|
||||
remote Sync files (remote push, remote pull)
|
||||
file Manage files (file list, file create, file delete, file rename)
|
||||
env Function env vars (env add, env list, env remove, env flush)
|
||||
account Account-level env vars (account env add, account env list, …)
|
||||
function Function extras (function logs, function execute, function ratelimit)
|
||||
storage Key-value store (storage create, storage list, storage set-item, …)
|
||||
cors CORS config (cors add, cors list, cors remove, cors clear)
|
||||
count Quick counts (count functions, count namespaces, …)
|
||||
req Requirements (req add, req remove)
|
||||
health Health check
|
||||
uiurl Print the dashboard URL
|
||||
|
||||
Discovery commands (no auth required):
|
||||
|
||||
shsf api openapi — print the full OpenAPI spec
|
||||
shsf mcp init — print MCP server config for this instance
|
||||
shsf mcp tools — list all available MCP tools
|
||||
shsf mcp docs — print the live function authoring reference
|
||||
shsf mcp call <tool> — call any MCP tool by name
|
||||
|
||||
Authentication is read from the environment:
|
||||
|
||||
SHSF_INSTANCE Base URL of your SHSF instance (e.g. https://shsf.example.com)
|
||||
SHSF_TOKEN API token for authenticated calls
|
||||
`;
|
||||
|
||||
export const instructDefinition = {
|
||||
name: "instruct",
|
||||
description:
|
||||
"IMPORTANT: Read this before using the CLI — SHSF platform overview, CLI command reference, and function authoring rules for humans and agents.",
|
||||
action: () => {
|
||||
// ── Human section ──────────────────────────────────────────────────────
|
||||
console.log(chalk.bold.cyan("\n╔══════════════════════════════════════════════╗"));
|
||||
console.log(chalk.bold.cyan("║ SHSF CLI — Getting Started ║"));
|
||||
console.log(chalk.bold.cyan("╚══════════════════════════════════════════════╝\n"));
|
||||
|
||||
console.log(chalk.bold("What is SHSF?"));
|
||||
console.log(
|
||||
"SHSF is a self-hosted serverless function platform. You deploy short-lived\n" +
|
||||
"functions (Python, Go, or .NET/C#) that are invoked over HTTP. The CLI lets\n" +
|
||||
"you manage functions, namespaces, files, environment variables, storage, and\n" +
|
||||
"more — all from the terminal or scripts.\n"
|
||||
);
|
||||
|
||||
console.log(chalk.bold("Quick start for humans:"));
|
||||
console.log(
|
||||
" 1. Set SHSF_INSTANCE and SHSF_TOKEN in your environment.\n" +
|
||||
" 2. Run shsf health to verify the connection.\n" +
|
||||
" 3. Run shsf create function to create your first function.\n" +
|
||||
" 4. Use shsf remote push to upload source files.\n" +
|
||||
" 5. Use shsf get exec-url to get the callable URL.\n" +
|
||||
" 6. Run shsf -h for the full command list at any time.\n"
|
||||
);
|
||||
|
||||
console.log(CLI_OVERVIEW);
|
||||
|
||||
// ── Agent section ───────────────────────────────────────────────────────
|
||||
console.log(chalk.bold.yellow("╔══════════════════════════════════════════════╗"));
|
||||
console.log(chalk.bold.yellow("║ FOR AI AGENTS — Function Authoring ║"));
|
||||
console.log(chalk.bold.yellow("╚══════════════════════════════════════════════╝\n"));
|
||||
|
||||
console.log(
|
||||
"If you are an AI agent writing or editing SHSF functions, the section below\n" +
|
||||
"is your authoritative reference. Follow every rule in §13 or the function\n" +
|
||||
"will fail to run. Use shsf mcp docs to fetch the live version of this\n" +
|
||||
"reference directly from the connected SHSF instance.\n"
|
||||
);
|
||||
|
||||
console.log(AIDOC);
|
||||
|
||||
console.log(chalk.dim("─────────────────────────────────────────────────────"));
|
||||
console.log(chalk.dim("Tip: run shsf mcp docs to fetch the live reference from your instance."));
|
||||
console.log(chalk.dim("Tip: run shsf -h to see all available commands.\n"));
|
||||
},
|
||||
};
|
||||
+8
-2
@@ -11,8 +11,14 @@ export const program = new Command();
|
||||
|
||||
program
|
||||
.name('shsf')
|
||||
.description('SHSF CLI tool to manage your serverless functions.')
|
||||
.version(pckg.version);
|
||||
.description(
|
||||
'SHSF CLI tool to manage your serverless functions.\n\n' +
|
||||
' NOTE: Run \'shsf instruct\' before getting started — it covers platform\n' +
|
||||
' concepts, CLI command overview, and function authoring rules for both\n' +
|
||||
' humans and AI agents.'
|
||||
)
|
||||
.version(pckg.version)
|
||||
.addHelpText('afterAll', '\nTip: run \'shsf instruct\' first to get a full platform and CLI overview.');
|
||||
|
||||
await resolveCommands();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user