--- phase: 09-tooling-portable-setup plan: 02 subsystem: setup tags: [bash, hermes, setup-script, provisioning, cron, skills] requires: - phase: 08-cron-reporting plan: 01 provides: archive-stale-sessions.sh script content, cron registration patterns (hermes cron create CLI syntax, DRY_RUN pattern) - phase: 08-cron-reporting plan: 02 provides: Weekly cron job patterns (ngn-weekly-stale-summary, ngn-weekly-archive) with 5-minute offset between summary and archive - phase: 07-main-session-skill provides: session skill SKILL.md content for embedding; hindsight_retain templates, Jira ticket creation pattern with epic cache - phase: 04-jira-skill provides: jira-query skill SKILL.md content for embedding provides: - ngn-agent/setup-ngn-agent.sh — 1340-line standalone portable setup script with embedded file snapshots - All 5 skill files + 2 reference files embedded as heredocs for self-contained re-creation - Config generation: config.yaml (via hermes config set + Python yaml), .env (with chmod 600), hindsight/config.json - 3 cron job registrations (ngn-daily-report, ngn-weekly-stale-summary, ngn-weekly-archive) - Interactive secret prompts with masked input (T-09-05 mitigation) - Best-effort error handling pattern for non-critical steps affects: - Phase 10+ (any phase needing to regenerate ngn-agent configuration on a new machine) tech-stack: added: [] patterns: - Standalone portable setup script with embedded heredocs (no external file dependencies) - Hybrid config generation: hermes config set for scalars + Python yaml (fallback sed) for arrays - prompt_secret function with env-var skip, masked input, loop-until-nonempty - Best-effort error handling: non-critical steps wrapped with || true - Progress indicator pattern [N/14] for step-by-step execution key-files: created: - ngn-agent/setup-ngn-agent.sh — 1340-line portable setup script modified: [] key-decisions: - "Each embedded file is a separate write function (write_session_init, write_jira_skill, etc.) — self-documenting and independently testable" - "Config.yaml uses hybrid approach: hermes config set for scalar keys, Python yaml module for arrays, sed fallback when yaml unavailable" - "Skill and script files embedded as heredocs with quoted delimiters ('EOF') — prevents variable expansion at script generation time" - "Cron registration wrapped with 2>/dev/null + 'may already exist' message — idempotent re-runs" - "Non-interactive mode (-y) reads secrets from environment variables with : ${VAR:?error} validation" patterns-established: - "Standalone portable setup script pattern: argument parsing → prereq checks → secret prompts → file generation → cron registration → restart offer" - "Embedded heredoc pattern: each file is a bash function with cat > path << 'QUOTED_DELIM' to prevent variable expansion in embedded content" - "Hybrid YAML generation: hermes config set for scalars, Python yaml for arrays, sed fallback" requirements-completed: [SETUP-01] duration: 4 min completed: 2026-06-15 --- # Phase 9 Plan 2: Portable ngn-agent Setup Script Summary **Portable 1340-line standalone bash setup script (ngn-agent/setup-ngn-agent.sh) for recreating all ngn-agent Hermes configuration on a fresh macOS machine — argument parsing, interactive secrets, config YAML/env/hindsight generation, all 5 skills + 2 scripts embedded, 3 cron jobs registered, gateway restart offer** ## Performance - **Duration:** 4 min - **Started:** 2026-06-15 23:26 +08 - **Completed:** 2026-06-15 23:30 +08 - **Tasks:** 3 - **Files modified:** 1 (1340 lines added) ## Accomplishments - Created `setup-ngn-agent.sh` (1340 lines) — fully self-contained, no external file dependencies - Argument parsing with getopts for 9 configurable parameters (SSH keys, repo paths, timezone, docker image) - Prerequisite validation: Hermes CLI on PATH, Docker running, SSH key file existence, repo path existence - Interactive masked secret prompts for JIRA_API_TOKEN, JIRA_EMAIL, TELEGRAM_BOT_TOKEN, OPENROUTER_API_KEY (T-09-05) - Config generation via hermes config set (scalars) + Python yaml (arrays) + sed fallback - .env generation with chmod 600 permissions (T-09-06) - hindsight/config.json with local_embedded mode, qwen/qwen3.5-9b model, hybrid memory - All 5 skills (jira, aws-diagnostics, confluence, bitbucket, session) + 2 reference files embedded as heredocs - Both scripts (session-init.sh, archive-stale-sessions.sh) embedded as heredocs with executable permission - 3 cron jobs registered with proper schedules and delivery methods - Config.yaml backup before modification (T-09-07) - Gateway restart offer at completion - Non-interactive mode (-y) for automated provisioning ## Task Commits Each task was committed atomically: 1. **Task 1: Create setup script skeleton — args, prereqs, and interactive prompts** - `2de51b1` (feat) 2. **Task 2: Implement config generation — config.yaml, .env, hindsight/config.json** - `9da9728` (feat) 3. **Task 3: Implement file/cron setup — scripts, skills, cron registration, gateway restart** - `5a8c183` (feat) ## Files Created/Modified - `ngn-agent/setup-ngn-agent.sh` — 1340-line standalone portable setup script (created) ## Decisions Made - **Embedded heredocs over base64**: All skill files, scripts, and reference files are embedded using heredocs with quoted delimiters (`'EOF'`) — prevents variable expansion at script generation time, keeps content human-readable without encoding overhead. Each file is a separate bash function for modularity and independent testing. - **Hybrid config.yaml generation**: `hermes config set` for scalar keys (docker_image, memory.provider, timezone, etc.) + Python yaml module for arrays (docker_volumes, shell_init_files, docker_forward_env). Python's yaml.safe_load → modify → yaml.dump preserves unknown keys and maintains proper YAML formatting. Fallback to sed-based injection if the `yaml` Python module is unavailable. - **Best-effort error handling**: The script uses `set -euo pipefail` for strict mode, but non-critical steps like cron registration are wrapped with `|| echo "⚠ ..."` — allowing the script to continue if a cron job already exists or if the Hermes CLI returns a non-fatal error. - **Prompt_secret with env-var skip**: Secret prompts check if the environment variable is already set before prompting (supports pre-exported secrets or non-interactive mode via `-y` flag). - **Cron job registration order**: Daily report first (most critical), then weekly summary, then weekly archive. Archive runs 5 minutes after summary (20:05 vs 20:00) per Phase 8 pattern to prevent race conditions. ## Deviations from Plan None — plan executed exactly as written. ## Issues Encountered None. All three tasks completed cleanly with syntax validation passing (`bash -n`). ## User Setup Required **External services require manual configuration.** See [09-USER-SETUP.md](./09-USER-SETUP.md) for: - Hermes CLI v0.16+ installation (pre-requisite) - JIRA_API_TOKEN from https://id.atlassian.com/manage/api-tokens - TELEGRAM_BOT_TOKEN from https://t.me/BotFather - OPENROUTER_API_KEY from https://openrouter.ai/keys The setup script handles interactive prompting for all 4 secrets. ## Threat Flags None — all threat mitigations from the plan's threat model are satisfied: - T-09-05 (Information Disclosure — secret exposure in terminal history): Mitigated — `read -s` for all secret prompts with masked input. - T-09-06 (Information Disclosure — .env world-readable secrets): Mitigated — `chmod 600` on .env immediately after writing. - T-09-07 (Tampering — config file corruption): Mitigated — backup existing config.yaml to `.bak.` before modification. - T-09-08 (Information Disclosure — terminal scrollback): Accepted — users responsible for terminal security. - T-09-09 (Tampering — cron prompt injection): Accepted — prompts embedded in setup script, not user-controllable. ## Next Phase Readiness - Phase 9 Plan 1 (Docker custom image) complete, Plan 2 (setup script) complete - Phase 9 fully complete — both Dockerfile + build script and portable setup script artifacts ready - User can run `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) - Ready for next phase (v1.1 milestone completion, validation, or v1.2 planning) ## Self-Check: PASSED | Check | Result | |-------|--------| | File exists | ✓ setup-ngn-agent.sh (1340 lines) | | File executable | ✓ | | Syntax validation (`bash -n`) | ✓ | | Task 1 commit (2de51b1) | ✓ | | Task 2 commit (9da9728) | ✓ | | Task 3 commit (5a8c183) | ✓ | | Script ≥ 300 lines | ✓ (1340 lines) | | `hermes cron create` count = 3 | ✓ | | Function names ≥ 8 matched | ✓ (14 matches) | | SUMMARY.md exists | ✓ | --- *Phase: 09-tooling-portable-setup* *Completed: 2026-06-15*