Files
Bagas Purwa Sentika d727c4dbce docs(09): create phase plan — custom Docker image + portable setup script
Phase 9 splits into two independent Wave 1 plans:
- 09-01: Custom Hermes Docker image (ngn-agent:latest) with aws-cli,
  terraform, helm, kubectl, and datadog CLI (pup), version-pinned
- 09-02: Portable setup-ngn-agent.sh with argument parsing,
  prerequisite checks, interactive secret prompts, config generation,
  skill/script embedding, and cron registration

Also marks Phase 8 as complete (cron reporting shipped 2026-06-15).
2026-06-15 23:13:35 +08:00

479 lines
24 KiB
Markdown

---
phase: 09-tooling-portable-setup
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
- ngn-agent/setup-ngn-agent.sh
autonomous: true
requirements: [SETUP-01]
user_setup:
- service: hermes
why: "Setup script assumes Hermes v0.16+ is installed"
env_vars:
- name: JIRA_API_TOKEN
source: "https://id.atlassian.com/manage/api-tokens"
- name: JIRA_EMAIL
source: "Your Atlassian account email"
- name: TELEGRAM_BOT_TOKEN
source: "https://t.me/BotFather — create a bot and copy the token"
- name: OPENROUTER_API_KEY
source: "https://openrouter.ai/keys (or reuse existing)"
must_haves:
truths:
- "User can run setup-ngn-agent.sh on a fresh macOS machine with Hermes installed"
- "Script validates prerequisites (Hermes on PATH, Docker running, SSH keys exist) before making changes"
- "Script prompts for all 4 secrets (JIRA_API_TOKEN, JIRA_EMAIL, TELEGRAM_BOT_TOKEN, OPENROUTER_API_KEY) with masked input"
- "Script accepts configurable paths via args or prompts (SSH keys, repo paths, timezone)"
- "After running, ~/.hermes/config.yaml has correct docker_volumes, shell_init_files, docker_forward_env, and docker_image"
- "After running, ~/.hermes/.env has all secrets and DEFAULT_REPOS"
- "After running, ~/.hermes/hindsight/config.json has Hindsight local_embedded config"
- "After running, ~/.hermes/scripts/ has session-init.sh and archive-stale-sessions.sh"
- "After running, ~/.hermes/skills/ngn-agent/ has all 5 skills with reference files"
- "After running, 3 cron jobs (ngn-daily-report, ngn-weekly-stale-summary, ngn-weekly-archive) are registered"
- "After running, docker_image in config.yaml points to ngn-agent:latest"
- "Script backups existing config.yaml before modifying"
- "Script offers to restart Hermes gateway at end"
artifacts:
- path: "ngn-agent/setup-ngn-agent.sh"
provides: "Portable one-shot macOS setup script for ngn-agent configuration"
min_lines: 300
key_links:
- from: "setup-ngn-agent.sh"
to: "~/.hermes/config.yaml"
via: "hermes config set + Python/sed for docker_volumes"
pattern: "hermes config set|config\\.yaml"
- from: "setup-ngn-agent.sh"
to: "~/.hermes/.env"
via: "cat/write secrets to .env"
pattern: "(JIRA_API_TOKEN|TELEGRAM_BOT_TOKEN)"
- from: "setup-ngn-agent.sh"
to: "~/.hermes/hindsight/config.json"
via: "write JSON config"
pattern: "hindsight/config\\.json"
- from: "setup-ngn-agent.sh"
to: "~/.hermes/scripts/"
via: "heredoc or cat file contents to scripts/"
pattern: "(session-init|archive-stale)"
- from: "setup-ngn-agent.sh"
to: "~/.hermes/skills/ngn-agent/"
via: "mkdir -p SKILL.md per skill"
pattern: "skills/ngn-agent"
- from: "setup-ngn-agent.sh"
to: "Hermes cron DB"
via: "hermes cron create"
pattern: "hermes cron create"
- from: "setup-ngn-agent.sh"
to: "Docker image"
via: "hermes config set terminal.docker_image"
pattern: "docker_image ngn-agent"
---
<objective>
**Portable ngn-agent Setup Script**
Create a single portable bash script (`ngn-agent/setup-ngn-agent.sh`) that can recreate all ngn-agent configuration on a fresh macOS machine with Hermes v0.16+ installed. The script handles prerequisite validation, interactive secret prompts, config file generation (config.yaml, .env, hindsight/config.json), skill/script file creation, cron job registration, and Docker image reference updates — all in one invocation.
**Purpose:** Enable a new machine to be fully configured with ngn-agent's workspace setup (SSH mounts, repo mounts, skills, cron reporting, hindsight memory) by running a single script with parameterized paths and interactive secret entry.
**Output:**
- `ngn-agent/setup-ngn-agent.sh` — Standalone portable setup script (self-contained, no external file dependencies)
</objective>
<execution_context>
@/Users/bapung/.config/opencode/gsd-core/workflows/execute-plan.md
@/Users/bapung/.config/opencode/gsd-core/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/09-tooling-portable-setup/09-CONTEXT.md
@.planning/phases/09-tooling-portable-setup/09-RESEARCH.md
@/Users/bapung/.hermes/config.yaml
@/Users/bapung/.hermes/.env
@/Users/bapung/.hermes/hindsight/config.json
@/Users/bapung/.hermes/scripts/session-init.sh
@/Users/bapung/.hermes/scripts/archive-stale-sessions.sh
@/Users/bapung/.hermes/skills/ngn-agent/jira/SKILL.md
@/Users/bapung/.hermes/skills/ngn-agent/aws-diagnostics/SKILL.md
@/Users/bapung/.hermes/skills/ngn-agent/confluence/SKILL.md
@/Users/bapung/.hermes/skills/ngn-agent/bitbucket/SKILL.md
@/Users/bapung/.hermes/skills/ngn-agent/session/SKILL.md
@/Users/bapung/.hermes/skills/ngn-agent/aws-diagnostics/references/multiregional-patterns.md
@/Users/bapung/.hermes/skills/ngn-agent/session/references/operational-monitoring.md
@.planning/phases/08-cron-reporting/08-01-SUMMARY.md
@.planning/phases/08-cron-reporting/08-02-SUMMARY.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create setup script skeleton — args, prereqs, and interactive prompts</name>
<files>ngn-agent/setup-ngn-agent.sh</files>
<action>
Create `ngn-agent/setup-ngn-agent.sh` starting with the script skeleton, argument parsing, prerequisite validation, and interactive secret prompts. This is the first part of the file (approximately first 120 lines).
**Script header:**
- Shebang: `#!/bin/bash` with `set -euo pipefail` (per D-06)
- Comment header block: `# setup-ngn-agent.sh — Portable ngn-agent configuration setup`
- Include: `# Phase 9, Plan 2 — recreates all configuration on a fresh macOS machine`
- Include: `# Assumes Hermes v0.16+ is installed (per D-07)`
- Include: `# Embedded file snapshots frozen at: $(date +%Y-%m-%d)` (per Common Pitfall 4)
**Argument parsing** (per D-09):
Use `getopts` for named arguments with defaults:
- `-s1 | --ssh-key-1` — SSH private key path 1 (default: `~/.ssh/id_ed25519razer`)
- `-s2 | --ssh-key-2` — SSH private key path 2 (default: `~/.ssh/id_rsa`)
- `-sc | --ssh-config` — SSH config path (default: `~/.ssh/config`)
- `-sh | --ssh-known-hosts` — SSH known_hosts path (default: `~/.ssh/known_hosts`)
- `-r1 | --repo-ops` — rai-ops repo path (default: `~/Razer/rai-ops`)
- `-r2 | --repo-deploy` — rai-deployment repo path (default: `~/Razer/rai-deployment`)
- `-r3 | --repo-devtools` — rai-devtools repo path (default: `~/Razer/rai-devtools`)
- `-t | --timezone` — Timezone (default: `Asia/Singapore`)
- `-d | --docker-image` — Docker image tag (default: `ngn-agent:latest`)
- `-y | --yes` — Non-interactive mode (skip prompts, use defaults for secrets if set via env)
- `-h | --help` — Show usage
Display usage info when `-h` is passed, showing all parameters with defaults.
**Prerequisite checks** (per CONTEXT.md "Specific Ideas" > "should validate prerequisites"):
1. Check Hermes CLI is installed: `command -v hermes >/dev/null 2>&1 || { echo "ERROR: Hermes not found — install v0.16+ first"; exit 1; }`
2. Check Docker is running: `docker info >/dev/null 2>&1 || { echo "ERROR: Docker not running"; exit 1; }`
3. Check SSH key files exist (the two key paths from args): test `-f` each, warn if missing but don't abort (user can skip keys).
4. Check repo paths exist: test `-d` each, warn if missing but don't abort.
5. Print a summary of paths being used.
**Interactive secret prompts** (per D-08):
Define a `prompt_secret` function:
- Args: var_name, prompt_text, is_optional (default: false)
- Use `read -s -p` for masked input (T-09-05 mitigation — no echo to terminal)
- If not optional, loop until non-empty value provided
- If the env var is already set (e.g., user exported it), skip the prompt
- Return the value via `echo`
Prompt for these secrets (D-08):
1. `JIRA_API_TOKEN` — required — "JIRA API Token (https://id.atlassian.com/manage/api-tokens): "
2. `JIRA_EMAIL` — required — "JIRA Email: "
3. `TELEGRAM_BOT_TOKEN` — required — "Telegram Bot Token (from @BotFather): "
4. `OPENROUTER_API_KEY` — optional (check if already set in env) — "OpenRouter API Key (leave blank to keep existing): "
5. `HINDSIGHT_LLM_API_KEY` — optional (defaults to same as OPENROUTER_API_KEY)
Store prompted values in variables for use in Task 2.
**Config directory creation:**
- `mkdir -p ~/.hermes/scripts`
- `mkdir -p ~/.hermes/hindsight`
- `mkdir -p ~/.hermes/skills/ngn-agent`
- `mkdir -p ~/.hermes/archive/sessions`
**Backup existing config** (per Anti-Pattern 4):
- If `~/.hermes/config.yaml` exists, copy to `~/.hermes/config.yaml.bak.$(date +%Y%m%d_%H%M%S)` before modifying (T-09-07 mitigation).
Make the script executable: `chmod +x /Users/bapung/Razer/ngn-agent/setup-ngn-agent.sh`.
**Embedded content strategy:**
- All skill files, script files, and reference files are embedded as heredocs (not base64 — bash heredocs with quoted delimiters preserve file content without encoding overhead for text files).
- Each embedded file is a bash function that can be called to write its content to the target path.
- The function names follow the pattern: `write_<name>` (e.g., `write_session_init`, `write_jira_skill`).
**Notes:**
- Reference D-06 through D-09 in comments where applicable.
- Use `echo " → [message]"` for progress output.
- Color/formatting: optional but keep simple (no dependencies).
</action>
<verify>
<automated>test -f /Users/bapung/Razer/ngn-agent/setup-ngn-agent.sh && head -20 /Users/bapung/Razer/ngn-agent/setup-ngn-agent.sh | grep -q 'setup-ngn-agent'</automated>
</verify>
<done>
- setup-ngn-agent.sh exists and is executable
- Argument parsing with getopts handles all 9 parameters with defaults
- Usage displayed with `-h`
- Prerequisite checks validate Hermes CLI, Docker, SSH key files, repo paths
- Interactive `prompt_secret` function implemented for masked input
- All 4 secrets prompted (JIRA_API_TOKEN, JIRA_EMAIL, TELEGRAM_BOT_TOKEN, OPENROUTER_API_KEY)
- Existing config.yaml is backed up before modification
- Embedded file write functions are defined (content filled in Task 2 and Task 3)
- D-06 through D-09 referenced in comments
</done>
</task>
<task type="auto">
<name>Task 2: Implement config generation — config.yaml, .env, hindsight/config.json</name>
<files>ngn-agent/setup-ngn-agent.sh</files>
<action>
Append (or fill in) the config generation functions in `setup-ngn-agent.sh`. These come after the Task 1 skeleton.
**Function: `generate_config_yaml`**
Write a new `~/.hermes/config.yaml` using `hermes config set` for simple keys and Python for complex YAML structures (per Research Pattern 3 — `hermes config set` for scalars, Python for arrays).
Keys to set via `hermes config set`:
- `terminal.backend docker`
- `terminal.docker_image ${DOCKER_IMAGE}` (default `ngn-agent:latest` — per D-10 "Update Docker image reference in config.yaml")
- `terminal.cwd /workspace`
- `terminal.container_memory 5120`
- `terminal.container_disk 51200`
- `terminal.container_cpu 1`
- `terminal.lifetime_seconds 300`
- `memory.provider hindsight`
- `terminal.timezone ${TIMEZONE}`
- `telegram.reactions false`
- `terminal.docker_env.AWS_REGION us-east-1`
- `terminal.container_persistent true`
- `terminal.docker_mount_cwd_to_workspace true`
For complex structures (docker_volumes array, shell_init_files, docker_forward_env), use Python 3 with `yaml` module. Write a Python script inline that:
1. Loads existing config.yaml (created by hermes config set calls)
2. Sets `terminal.docker_volumes` to the list:
```
"${SSH_KEY_1}:/root/.ssh/id_ed25519razer:ro",
"${SSH_KEY_2}:/root/.ssh/id_rsa:ro",
"${SSH_CONFIG}:/root/.ssh/config:ro",
"${SSH_KNOWN_HOSTS}:/root/.ssh/known_hosts:ro",
"${HOME}/.aws/config:/root/.aws/config:ro",
"${HOME}/.aws/sso/cache:/root/.aws/sso/cache:rw",
"${REPO_OPS}:/workspace/rai-ops:rw",
"${REPO_DEPLOY}:/workspace/rai-deployment:rw",
"${REPO_DEVTOOLS}:/workspace/rai-devtools:rw",
"${HOME}/.hermes/scripts:/usr/local/bin:ro",
```
3. Sets `terminal.docker_forward_env` to `['JIRA_EMAIL', 'JIRA_API_TOKEN', 'DEFAULT_REPOS']`
4. Sets `terminal.shell_init_files` to `['/usr/local/bin/session-init.sh']`
5. Writes back to config.yaml
If `python3` + `yaml` module is not available, fall back to a `sed`-based approach using heredoc templates.
**Function: `generate_env_file`**
Write `~/.hermes/.env` with:
1. Comment header: `# ngn-agent Environment — generated by setup-ngn-agent.sh`
2. Required vars (D-08):
- `OPENROUTER_API_KEY=<value>` (if provided)
- `JIRA_API_TOKEN=<value>`
- `JIRA_EMAIL=<value>`
- `TELEGRAM_BOT_TOKEN=<value>`
- `HINDSIGHT_LLM_API_KEY=<value>` (defaults to OPENROUTER_API_KEY if not separately provided)
3. Config vars:
- `DEFAULT_REPOS=rai-ops,rai-deployment,rai-devtools`
- `TELEGRAM_ALLOWED_USERS=474440517`
- `TERMINAL_TIMEOUT=60`
- `TERMINAL_LIFETIME_SECONDS=300`
4. Set file permissions: `chmod 600 ~/.hermes/.env` (T-09-06 mitigation — prevent world-readable secrets)
Include comment separators between sections matching the original .env style.
**Function: `generate_hindsight_config`**
Write `~/.hermes/hindsight/config.json` with exact content from current config (D-10):
```json
{
"mode": "local_embedded",
"llm_provider": "openrouter",
"llm_base_url": "https://openrouter.ai/api/v1",
"llm_model": "qwen/qwen3.5-9b",
"bank_id": "hermes",
"recall_budget": "low",
"recall_prefetch_method": "recall",
"auto_recall": true,
"recall_types": "observation",
"auto_retain": true,
"retain_async": true,
"retain_every_n_turns": 5,
"memory_mode": "hybrid"
}
```
**Function: `generate_cron_env_config`**
Ensure cron has the required env vars by running:
- `hermes config set cron.env.JIRA_EMAIL "${JIRA_EMAIL}"`
- `hermes config set cron.env.JIRA_API_TOKEN "${JIRA_API_TOKEN}"`
**Definition order:** The functions are defined first, then called from the main execution block at the bottom of the script.
**Notes:**
- Reference D-10 for each section it creates/updates.
- If the baseline config.yaml structure changes (e.g., Hermes adds a new required field), the Python YAML script should preserve unknown keys (load, modify, dump — not overwrite completely).
- After writing config.yaml, validate with `hermes config get terminal.docker_image` to confirm it was set.
- Set `chmod 600` on .env immediately after writing (T-09-06).
</action>
<verify>
<automated>grep -c 'generate_config_yaml\|generate_env_file\|generate_hindsight_config' /Users/bapung/Razer/ngn-agent/setup-ngn-agent.sh</automated>
</verify>
<done>
- `generate_config_yaml` sets all config.yaml keys using hermes config set + Python YAML
- `generate_env_file` writes all secrets and DEFAULT_REPOS to .env with chmod 600
- `generate_hindsight_config` writes hindsight/config.json
- Docker image reference in config.yaml is updated to ngn-agent:latest (D-10)
- Cron env vars (JIRA_EMAIL, JIRA_API_TOKEN) are configured
- D-10 referenced in comments for each section
</done>
</task>
<task type="auto">
<name>Task 3: Implement file/cron setup — scripts, skills, cron registration, gateway restart</name>
<files>ngn-agent/setup-ngn-agent.sh</files>
<action>
Append the file writing functions and cron registration to `setup-ngn-agent.sh`. These complete the setup script.
**Function: `write_session_init_script`**
Write `~/.hermes/scripts/session-init.sh` with the exact content from the current file (37 lines). This script verifies DEFAULT_REPOS mounts at session start. Use a heredoc with a quoted delimiter (`'EOF'`) to prevent variable expansion:
```bash
cat > ~/.hermes/scripts/session-init.sh << 'SCRIPT'
#!/bin/bash
# session-init.sh — Verify DEFAULT_REPOS mounts at session start
# ... (exact content)
SCRIPT
chmod +x ~/.hermes/scripts/session-init.sh
```
**Function: `write_archive_script`**
Same approach for `~/.hermes/scripts/archive-stale-sessions.sh` (41 lines) with `DRY_RUN=true` default and `set -euo pipefail`.
**Function: `write_skill_files`**
For each of the 5 skills (per D-10: all 5 skill directories), create the directory and write the SKILL.md:
1. `~/.hermes/skills/ngn-agent/jira/SKILL.md`
2. `~/.hermes/skills/ngn-agent/aws-diagnostics/SKILL.md`
3. `~/.hermes/skills/ngn-agent/confluence/SKILL.md`
4. `~/.hermes/skills/ngn-agent/bitbucket/SKILL.md`
5. `~/.hermes/skills/ngn-agent/session/SKILL.md`
Use heredocs with quoted delimiters to write each file with exact content from the current source files. For `aws-diagnostics` and `session` skills, also create their reference directories and files:
- `~/.hermes/skills/ngn-agent/aws-diagnostics/references/multiregional-patterns.md`
- `~/.hermes/skills/ngn-agent/session/references/operational-monitoring.md`
**Function: `register_cron_jobs`**
Register 3 cron jobs (D-10) using `hermes cron create` with the exact syntax verified in Phase 8:
1. `ngn-daily-report` (per Phase 8 Plan 2 summary):
```
hermes cron create --deliver telegram --skill session --skill jira-query \
'0 9 * * *' \
'Daily session report. Export sessions, find active ones, check Jira, compose Telegram summary.'
```
Note: Use the exact cron registration pattern from Phase 8 SUMMARYs:
- Skill-backed: `--deliver telegram --skill <name> 'schedule' 'prompt'`
- The `ngn-weekly-stale-summary` and `ngn-weekly-archive` from Phase 8 Plan 2
2. `ngn-weekly-stale-summary`:
```
hermes cron create --deliver telegram --skill session \
'0 20 * * 0' \
'Weekly stale session summary. ...'
```
3. `ngn-weekly-archive`:
```
hermes cron create --no-agent --script archive-stale-sessions.sh \
'5 20 * * 0'
```
**Function: `offer_gateway_restart`**
At the end of the script, after all configuration is complete (per CONTEXT.md "Specific Ideas"):
```bash
echo ""
echo "==> Setup complete!"
echo ""
read -p "Restart Hermes gateway now? [Y/n]: " restart
if [[ "$restart" =~ ^[Yy]?$ ]]; then
hermes gateway restart
echo " → Gateway restarted."
else
echo " → Skipped. Run 'hermes gateway restart' when ready."
fi
```
**Main execution block:**
At the bottom of the script, add the main execution flow that calls all functions in order:
1. Parse arguments (Task 1)
2. Check prerequisites (Task 1)
3. Prompt for secrets (Task 1)
4. Create directories (Task 1)
5. Backup existing config (Task 1)
6. Generate config.yaml (Task 2)
7. Generate .env (Task 2)
8. Generate hindsight config (Task 2)
9. Generate cron env config (Task 2)
10. Write session-init script (Task 3)
11. Write archive script (Task 3)
12. Write skill files (Task 3)
13. Register cron jobs (Task 3)
14. Offer gateway restart (Task 3)
Each step should print a progress indicator like `[1/14] Checking prerequisites...`.
**Error handling:**
- If any step fails (non-zero exit), print a warning but continue (best-effort) unless it's a critical prerequisite.
- The `set -euo pipefail` at the top means any failure exits unless explicitly handled with `|| true`.
- Wrap non-critical steps: `register_cron_jobs || echo " ⚠ Cron registration had issues (may already exist)"`.
**Notes:**
- Reference D-10 for the full list of what the script creates/updates.
- Add a lifecycle comment at the top: "Embedded file snapshots frozen at: $(date +%Y-%m-%d) — Regenerate by re-running this phase."
- Test the script after writing: if Docker is running, do a dry-run check with `bash -n setup-ngn-agent.sh` to validate syntax.
</action>
<verify>
<automated>bash -n /Users/bapung/Razer/ngn-agent/setup-ngn-agent.sh</automated>
</verify>
<done>
- All 5 skill SKILL.md files are embedded as heredocs
- 2 reference files (multiregional-patterns.md, operational-monitoring.md) are embedded
- 2 scripts (session-init.sh, archive-stale-sessions.sh) are embedded and made executable
- 3 cron jobs are registered via hermes cron create
- Gateway restart offer is at the end
- Script passes `bash -n` syntax validation
- D-10 is referenced in comments for each section it creates/updates
- Script is fully self-contained (no external file read dependencies)
</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| Terminal (stdin) → script | User types secrets via read -s — masked input, no echo |
| Script → ~/.hermes/.env | Secrets written to plaintext file at rest |
| Script → Hermes cron DB | Cron job registration via hermes CLI |
| Script → ~/.hermes/config.yaml | Config YAML generation |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-09-05 | Information Disclosure | Secret exposure in terminal history | mitigate | `read -s` for all secret prompts (masked input, no echo to terminal) |
| T-09-06 | Information Disclosure | ~/.hermes/.env world-readable secrets | mitigate | `chmod 600` on .env immediately after writing |
| T-09-07 | Tampering | Config file corruption from partial write | mitigate | Backup existing config.yaml to `.bak.<timestamp>` before modification |
| T-09-08 | Information Disclosure | Secrets captured in terminal scrollback | accept | Users are responsible for terminal security on their own machines |
| T-09-09 | Tampering | Cron job with malicious prompt | accept | Cron prompts are embedded in the setup script, not user-controllable |
## Package Legitimacy Gate
| Package | Registry | Verdict | Disposition |
|---------|----------|---------|-------------|
| (none) | — | — | No npm/pip/cargo packages installed. All operations via bash built-ins, hermes CLI, and Python stdlib. |
</threat_model>
<verification>
- Automated: `bash -n /Users/bapung/Razer/ngn-agent/setup-ngn-agent.sh` passes (syntax check)
- Automated: `grep -c 'hermes cron create' setup-ngn-agent.sh` returns 3 (all cron jobs)
- Automated: `grep -c 'write_session_init\|write_archive_script\|write_jira_skill\|write_aws_skill\|write_confluence_skill\|write_bitbucket_skill\|write_session_skill' setup-ngn-agent.sh` returns 8 (all scripts + 5 skills + 2 ref files)
- Manual: User can inspect `setup-ngn-agent.sh --help` to see all parameters
- Dry-run: User can run `bash -x setup-ngn-agent.sh` to trace execution (no destructive test needed)
</verification>
<success_criteria>
1. setup-ngn-agent.sh exists, is executable, and passes bash syntax validation
2. Script accepts all 9 parameters via getopts with documented defaults
3. Prerequisites checks for Hermes CLI, Docker, SSH keys
4. All 4 secrets prompted with masked input
5. Config generation: config.yaml, .env, hindsight/config.json
6. All 5 skill directories + SKILL.md files + reference files embedded and written
7. Both scripts (session-init.sh, archive-stale-sessions.sh) embedded and written
8. All 3 cron jobs registered (ngn-daily-report, ngn-weekly-stale-summary, ngn-weekly-archive)
9. Docker image reference updated to ngn-agent:latest
10. Existing config.yaml backed up before modification
11. Gateway restart offered at completion
12. D-06 through D-10 referenced in comments for traceability
</success_criteria>
</objective>