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).
This commit is contained in:
478
.planning/phases/09-tooling-portable-setup/09-02-PLAN.md
Normal file
478
.planning/phases/09-tooling-portable-setup/09-02-PLAN.md
Normal file
@@ -0,0 +1,478 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user