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:
@@ -17,14 +17,14 @@
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 🚧 v1.1 Session Lifecycle, Memory & Reporting (In Planning)
|
### 🚧 v1.1 Session Lifecycle, Memory & Reporting (In Progress)
|
||||||
|
|
||||||
**Milestone Goal:** Productionize session workspace with default repos, upgrade to persistent cross-session memory (hindsight), operationalize daily reporting with session lifecycle management, and provide portable setup script with essential tools.
|
**Milestone Goal:** Productionize session workspace with default repos, upgrade to persistent cross-session memory (hindsight), operationalize daily reporting with session lifecycle management, and provide portable setup script with essential tools.
|
||||||
|
|
||||||
- [x] **Phase 5: Hindsight Memory Provider** — Cross-session persistent memory with entity-aware recall via Hindsight local_embedded
|
- [x] **Phase 5: Hindsight Memory Provider** — Cross-session persistent memory with entity-aware recall via Hindsight local_embedded
|
||||||
- [x] **Phase 6: Default Repos & SSH Mount** — DEFAULT_REPOS mounted via host filesystem + SSH credential mounting
|
- [x] **Phase 6: Default Repos & SSH Mount** — DEFAULT_REPOS mounted via host filesystem + SSH credential mounting
|
||||||
- [x] **Phase 7: Main Session Skill** — Session lifecycle orchestration skill covering init-to-close workflow
|
- [x] **Phase 7: Main Session Skill** — Session lifecycle orchestration skill covering init-to-close workflow
|
||||||
- [ ] **Phase 8: Cron Reporting** — Daily session summaries, stale session archiving, and Jira integration
|
- [x] **Phase 8: Cron Reporting** — Daily session summaries, stale session archiving, and Jira integration
|
||||||
- [ ] **Phase 9: Tooling & Portable Setup** — Custom Docker image with AWS CLI, Terraform, Helm, kubectl, Datadog CLI + portable setup script
|
- [ ] **Phase 9: Tooling & Portable Setup** — Custom Docker image with AWS CLI, Terraform, Helm, kubectl, Datadog CLI + portable setup script
|
||||||
|
|
||||||
## Phase Details
|
## Phase Details
|
||||||
@@ -99,7 +99,11 @@ Plans:
|
|||||||
3. Portable setup script (`setup-ngn-agent.sh`) recreates all config (hindsight, repos, SSH, skills, cron) on a fresh machine
|
3. Portable setup script (`setup-ngn-agent.sh`) recreates all config (hindsight, repos, SSH, skills, cron) on a fresh machine
|
||||||
4. Setup script accepts SSH key path and repo paths as parameters (no hardcoded paths)
|
4. Setup script accepts SSH key path and repo paths as parameters (no hardcoded paths)
|
||||||
5. After running setup script + gateway restart, a new session has all tools, repos, and skills working
|
5. After running setup script + gateway restart, a new session has all tools, repos, and skills working
|
||||||
**Plans**: TBD
|
**Plans**: 2 plans
|
||||||
|
|
||||||
|
Plans:
|
||||||
|
- [ ] 09-01-PLAN.md — Custom Docker image with 5 platform tools + build script (Wave 1)
|
||||||
|
- [ ] 09-02-PLAN.md — Portable setup script recreating all config on fresh machine (Wave 1)
|
||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
@@ -112,5 +116,5 @@ Plans:
|
|||||||
| 5. Hindsight Memory Provider | v1.1 | 1/1 | Complete | 2026-06-14 |
|
| 5. Hindsight Memory Provider | v1.1 | 1/1 | Complete | 2026-06-14 |
|
||||||
| 6. Default Repos & SSH Mount | v1.1 | 1/1 | Complete | 2026-06-14 |
|
| 6. Default Repos & SSH Mount | v1.1 | 1/1 | Complete | 2026-06-14 |
|
||||||
| 7. Main Session Skill | v1.1 | 1/1 | Complete | 2026-06-14 |
|
| 7. Main Session Skill | v1.1 | 1/1 | Complete | 2026-06-14 |
|
||||||
| 8. Cron Reporting | v1.1 | 0/2 | Not started | - |
|
| 8. Cron Reporting | v1.1 | 2/2 | Complete | 2026-06-15 |
|
||||||
| 9. Tooling & Portable Setup | v1.1 | 0/TBD | Not started | - |
|
| 9. Tooling & Portable Setup | v1.1 | 0/2 | Not started | - |
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ gsd_state_version: 1.0
|
|||||||
milestone: v1.1
|
milestone: v1.1
|
||||||
milestone_name: Session Lifecycle, Memory & Reporting
|
milestone_name: Session Lifecycle, Memory & Reporting
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: Phase 7 complete — session skill created
|
stopped_at: Phase 9 context gathered
|
||||||
last_updated: "2026-06-15T14:44:17.573Z"
|
last_updated: "2026-06-15T15:03:12.180Z"
|
||||||
last_activity: 2026-06-15 -- Phase 08 execution started
|
last_activity: 2026-06-15 -- Phase 08 execution started
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 3
|
completed_phases: 4
|
||||||
total_plans: 5
|
total_plans: 5
|
||||||
completed_plans: 3
|
completed_plans: 5
|
||||||
percent: 60
|
percent: 80
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -70,7 +70,7 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-06-15T12:28:17.967Z
|
Last session: 2026-06-15T15:03:12.173Z
|
||||||
Stopped at: Phase 7 complete — session skill created
|
Stopped at: Phase 9 context gathered
|
||||||
Resume file: .planning/phases/07-main-session-skill/07-01-SUMMARY.md
|
Resume file: .planning/phases/09-tooling-portable-setup/09-CONTEXT.md
|
||||||
Next action: /gsd-plan-phase 5 (Hindsight Memory Provider)
|
Next action: /gsd-plan-phase 5 (Hindsight Memory Provider)
|
||||||
|
|||||||
224
.planning/phases/09-tooling-portable-setup/09-01-PLAN.md
Normal file
224
.planning/phases/09-tooling-portable-setup/09-01-PLAN.md
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
---
|
||||||
|
phase: 09-tooling-portable-setup
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- ngn-agent/docker/Dockerfile
|
||||||
|
- ngn-agent/docker/build.sh
|
||||||
|
autonomous: true
|
||||||
|
requirements: [TOOL-01]
|
||||||
|
|
||||||
|
must_haves:
|
||||||
|
truths:
|
||||||
|
- "Custom Docker image can be built with a single command (docker/build.sh)"
|
||||||
|
- "Built image includes aws-cli v2, terraform, helm, kubectl, and datadog CLI (pup)"
|
||||||
|
- "Image is tagged ngn-agent:latest (local only, no registry push)"
|
||||||
|
- "Each tool version is pinned for reproducibility"
|
||||||
|
- "Build uses Dockerfile from the project repo (ngn-agent/docker/Dockerfile)"
|
||||||
|
artifacts:
|
||||||
|
- path: "ngn-agent/docker/Dockerfile"
|
||||||
|
provides: "Custom Hermes-compatible Docker image definition with 5 platform tools"
|
||||||
|
min_lines: 80
|
||||||
|
- path: "ngn-agent/docker/build.sh"
|
||||||
|
provides: "Single-command image build entry point"
|
||||||
|
min_lines: 15
|
||||||
|
key_links:
|
||||||
|
- from: "ngn-agent/docker/build.sh"
|
||||||
|
to: "ngn-agent/docker/Dockerfile"
|
||||||
|
via: "docker build -f"
|
||||||
|
pattern: "docker build.*-f.*Dockerfile"
|
||||||
|
- from: "Dockerfile"
|
||||||
|
to: "aws-cli v2"
|
||||||
|
via: "curl → unzip → aws/install"
|
||||||
|
pattern: "awscli\\.amazonaws\\.com/awscli-exe"
|
||||||
|
- from: "Dockerfile"
|
||||||
|
to: "terraform"
|
||||||
|
via: "HashiCorp apt repo"
|
||||||
|
pattern: "apt\\.releases\\.hashicorp\\.com"
|
||||||
|
- from: "Dockerfile"
|
||||||
|
to: "helm"
|
||||||
|
via: "Buildkite apt repo"
|
||||||
|
pattern: "packages\\.buildkite\\.com/helm"
|
||||||
|
- from: "Dockerfile"
|
||||||
|
to: "kubectl"
|
||||||
|
via: "Google Kubernetes apt repo"
|
||||||
|
pattern: "pkgs\\.k8s\\.io"
|
||||||
|
- from: "Dockerfile"
|
||||||
|
to: "pup (Datadog CLI)"
|
||||||
|
via: "GitHub releases binary download"
|
||||||
|
pattern: "github\\.com/DataDog/pup/releases"
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
**Custom Hermes Docker Image with Platform Engineering Tools**
|
||||||
|
|
||||||
|
Create a custom Docker image extending `nikolaik/python-nodejs:python3.11-nodejs20` with five platform engineering CLI tools pre-installed: AWS CLI v2, Terraform, Helm, kubectl, and Datadog CLI (pup). The image is buildable with a single `docker/build.sh` command and tagged `ngn-agent:latest` for local use.
|
||||||
|
|
||||||
|
**Purpose:** Eliminate per-session tool installation overhead — tools are baked into the Docker image so every Hermes session has immediate access to aws-cli, terraform, helm, kubectl, and pup without runtime installs.
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
- `ngn-agent/docker/Dockerfile` — Version-pinned tool installations on top of the base Hermes image
|
||||||
|
- `ngn-agent/docker/build.sh` — Single-command build entry point
|
||||||
|
</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
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Create Dockerfile with version-pinned tool installations</name>
|
||||||
|
<files>ngn-agent/docker/Dockerfile</files>
|
||||||
|
<action>
|
||||||
|
Create `ngn-agent/docker/Dockerfile` that:
|
||||||
|
|
||||||
|
1. **FROM** extends `nikolaik/python-nodejs:python3.11-nodejs20` (per D-01). Add a comment above FROM noting: "D-01: Base image tag python3.11-nodejs20 — verify availability at build time; if manifest not found, update to python3.11-nodejs22-bookworm (Node.js 20 EOL April 2026)."
|
||||||
|
|
||||||
|
2. **LABEL** with `description="ngn-agent: Custom Hermes Docker image with platform engineering tools"` and `maintainer="ngn-agent"`.
|
||||||
|
|
||||||
|
3. **ARGs for version pinning** (per D-02):
|
||||||
|
- `TERRAFORM_VERSION=1.15.6`
|
||||||
|
- `HELM_VERSION=4.2.1`
|
||||||
|
- `KUBECTL_VERSION=1.36.1`
|
||||||
|
- `PUPP_VERSION=1.1.0`
|
||||||
|
(AWS CLI v2 is the latest stable — per D-03, install without version pinning but pin to latest known at time of build.)
|
||||||
|
|
||||||
|
4. **Install system dependencies** in a single RUN:
|
||||||
|
`curl`, `ca-certificates`, `unzip`, `gnupg`, `wget` — clean apt lists after install.
|
||||||
|
|
||||||
|
5. **Install AWS CLI v2** (per D-03):
|
||||||
|
Use the official curl → unzip → `./aws/install` method (no apt repo for v2). Install to `/usr/local/bin` and `/usr/local/aws-cli`. Clean up zip and extracted files. Reference D-03 in a comment.
|
||||||
|
|
||||||
|
6. **Install Terraform** (per D-03):
|
||||||
|
Add HashiCorp GPG key, add HashiCorp apt repo, `apt-get install -y terraform=${TERRAFORM_VERSION}`. Clean apt lists. Reference D-03.
|
||||||
|
|
||||||
|
7. **Install kubectl** (per D-03):
|
||||||
|
Add Google Kubernetes GPG key, add kubernetes apt repo for v1.36, `apt-get install -y kubectl`. Do NOT version-pin kubectl (it must match the target cluster version — per D-03: "latest stable matching cluster version"). Clean apt lists. Reference D-03.
|
||||||
|
|
||||||
|
8. **Install Helm** (per D-03):
|
||||||
|
Add Buildkite GPG key, add Helm apt repo, `apt-get install -y helm=${HELM_VERSION}`. Clean apt lists. Reference D-03.
|
||||||
|
|
||||||
|
9. **Install Datadog CLI (pup)** (per D-03):
|
||||||
|
Download the Linux x86_64 tarball from GitHub Releases, extract `pup` binary to `/usr/local/bin/`, clean up. Reference D-03.
|
||||||
|
|
||||||
|
10. **Verify step**: Single RUN with `echo "=== Tool versions ===" && aws --version && terraform --version && helm version --short && kubectl version --client --output=yaml 2>/dev/null | grep gitVersion && pup --version`. Use `|| true` on version checks that may exit non-zero so build doesn't fail on a single tool being unreachable.
|
||||||
|
|
||||||
|
11. **CMD** `["bash"]` — matching base image behavior.
|
||||||
|
|
||||||
|
**Build hygiene:**
|
||||||
|
- Do NOT `COPY .` or any full-directory copy — this prevents leaking secrets into image layers (T-09-02 mitigation).
|
||||||
|
- Order tool installs from most-frequently-changed to least-changed to optimize layer caching.
|
||||||
|
- Use `--no-install-recommends` on all apt-get install commands.
|
||||||
|
- Remove apt lists after each apt install to keep image small.
|
||||||
|
- All tool downloads use HTTPS URLs (T-09-01 mitigation).
|
||||||
|
- Add inline comments referencing each D-NN decision for traceability.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>test -f /Users/bapung/Razer/ngn-agent/docker/Dockerfile && wc -l /Users/bapung/Razer/ngn-agent/docker/Dockerfile</automated>
|
||||||
|
</verify>
|
||||||
|
<done>
|
||||||
|
- Dockerfile exists at ngn-agent/docker/Dockerfile
|
||||||
|
- All 5 tools (aws-cli, terraform, helm, kubectl, pup) are installed via RUN commands
|
||||||
|
- Tool versions are pinned via ARGs (except kubectl which matches cluster version)
|
||||||
|
- D-01 through D-03 are referenced in comments
|
||||||
|
- No `COPY .` or directory-wide copy present
|
||||||
|
</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Create build.sh and verify image builds successfully</name>
|
||||||
|
<files>ngn-agent/docker/build.sh</files>
|
||||||
|
<action>
|
||||||
|
Create `ngn-agent/docker/build.sh` (per D-04):
|
||||||
|
|
||||||
|
1. Shebang: `#!/bin/bash` with `set -euo pipefail`.
|
||||||
|
|
||||||
|
2. Constants:
|
||||||
|
- `IMAGE_NAME="ngn-agent"`
|
||||||
|
- `IMAGE_TAG="latest"`
|
||||||
|
- `DOCKER_DIR` resolved from script location: `"$(cd "$(dirname "$0")" && pwd)"`
|
||||||
|
|
||||||
|
3. Print build banner: `echo "==> Building ${IMAGE_NAME}:${IMAGE_TAG}..."`
|
||||||
|
|
||||||
|
4. `docker build` command:
|
||||||
|
- `-t "${IMAGE_NAME}:${IMAGE_TAG}"`
|
||||||
|
- `-f "${DOCKER_DIR}/Dockerfile"`
|
||||||
|
- Build context: `"${DOCKER_DIR}"` (not the repo root — prevents leaking files)
|
||||||
|
- Per D-05: tag is `ngn-agent:latest` (local only, no registry push)
|
||||||
|
|
||||||
|
5. Print completion banner: `echo "==> Build complete: ${IMAGE_NAME}:${IMAGE_TAG}"` followed by `docker images "${IMAGE_NAME}:${IMAGE_TAG}"`.
|
||||||
|
|
||||||
|
6. Make the script executable: `chmod +x /Users/bapung/Razer/ngn-agent/docker/build.sh`.
|
||||||
|
|
||||||
|
**Verify the build** by running `docker/build.sh` (or `bash docker/build.sh` if script path issues). If the base image tag `python3.11-nodejs20` fails with a manifest error, update the Dockerfile FROM line to `nikolaik/python-nodejs:python3.11-nodejs22-bookworm` as recommended by research, add a comment noting the change, and retry. After successful build:
|
||||||
|
|
||||||
|
- Run `docker run --rm ngn-agent:latest aws --version` — confirms aws-cli is installed and executable
|
||||||
|
- Run `docker run --rm ngn-agent:latest terraform --version` — confirms terraform works
|
||||||
|
- Run `docker run --rm ngn-agent:latest helm version --short` — confirms helm works
|
||||||
|
- Run `docker run --rm ngn-agent:latest kubectl version --client` — confirms kubectl works
|
||||||
|
- Run `docker run --rm ngn-agent:latest pup --version` — confirms pup works
|
||||||
|
|
||||||
|
If any tool fails in the container, fix the Dockerfile and rebuild. The image must have all 5 tools working.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
<automated>docker run --rm ngn-agent:latest sh -c 'aws --version && terraform --version && helm version --short && kubectl version --client && pup --version'</automated>
|
||||||
|
</verify>
|
||||||
|
<done>
|
||||||
|
- build.sh exists and is executable
|
||||||
|
- `ngn-agent:latest` image builds successfully
|
||||||
|
- All 5 tools execute correctly inside the container
|
||||||
|
- Build script references D-04 and D-05 decisions
|
||||||
|
- If base image tag was updated to python3.11-nodejs22-bookworm due to deprecation, the FROM line is updated and a comment explains the change
|
||||||
|
</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<threat_model>
|
||||||
|
## Trust Boundaries
|
||||||
|
|
||||||
|
| Boundary | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| Docker build host → Docker daemon | Docker context is read by build daemon |
|
||||||
|
| Docker build → external tool repos | Tool downloads cross HTTPS boundaries |
|
||||||
|
| Docker image layers → local storage | Built image stored on host filesystem |
|
||||||
|
|
||||||
|
## STRIDE Threat Register
|
||||||
|
|
||||||
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||||
|
|-----------|----------|-----------|-------------|-----------------|
|
||||||
|
| T-09-01 | Tampering | Tool download MITM (curl/wget from S3, GitHub, apt repos) | mitigate | All downloads use HTTPS. apt repos use GPG key verification to sign packages. |
|
||||||
|
| T-09-02 | Information Disclosure | Build context leak (COPY . could send .env into Docker daemon) | mitigate | Build context is `docker/` directory only — not repo root. Dockerfile does not COPY . anywhere. |
|
||||||
|
| T-09-03 | Tampering | Base image supply chain (nikolaik/python-nodejs) | accept | Widely used community image; no custom base image available. |
|
||||||
|
| T-09-04 | Denial of Service | Base image tag python3.11-nodejs20 may not exist | mitigate | Dockerfile comment flags potential deprecation. If build fails with manifest error, update to python3.11-nodejs22-bookworm. |
|
||||||
|
|
||||||
|
## Package Legitimacy Gate
|
||||||
|
|
||||||
|
| Package | Registry | Verdict | Disposition |
|
||||||
|
|---------|----------|---------|-------------|
|
||||||
|
| (none) | — | — | No npm/pip/cargo packages installed. All tools via apt or curl binary downloads. |
|
||||||
|
</threat_model>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
- Automated: `docker run --rm ngn-agent:latest sh -c 'aws --version && terraform --version && helm version --short && kubectl version --client && pup --version'` passes with all 5 tools
|
||||||
|
- Manual: User can inspect `docker/images` output to confirm tag and creation date
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
1. The image `ngn-agent:latest` exists in local Docker daemon
|
||||||
|
2. Running `docker run --rm ngn-agent:latest <tool> --version` succeeds for all 5 tools
|
||||||
|
3. `docker/build.sh` is the single entry point for rebuilding
|
||||||
|
4. Both files are committed to the ngn-agent git repo
|
||||||
|
5. Tool versions are pinned (ARGS in Dockerfile) for future reproducibility
|
||||||
|
</success_criteria>
|
||||||
|
</objective>
|
||||||
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