The artifact pipeline

Save, search, verify, truncate, scan. Every artifact goes through the same pipeline.

save-artifact.sh

When a phase completes, the agent calls save-artifact.sh with the phase name and a JSON file. The script runs six steps before anything touches disk:

Input JSON
  │
  ├─ 1. Validate    → Is it valid JSON? Does it have required fields?
  │                    Required: phase, summary. Rejects malformed input.
  │
  ├─ 2. Secret scan → Does any value match a known secret pattern?
  │                    Redacts matches, logs a warning.
  │
  ├─ 3. Truncate    → Is the artifact larger than the findings limit?
  │                    Default: 50 findings max. Configurable via NANOSTACK_MAX_FINDINGS.
  │
  ├─ 4. Enrich      → Adds timestamp, project name, branch, git SHA.
  │                    Project = basename of git root. Branch = current HEAD.
  │
  ├─ 5. Integrity   → Computes SHA-256 of the final content.
  │                    Stored in the "integrity" field.
  │
  └─ 6. Write       → Writes to the store path.
                       Filename: {phase}-{timestamp}.json

Usage:

# Save a review artifact
bin/save-artifact.sh review review-findings.json

# Save with a custom store path
NANOSTACK_STORE=/shared/artifacts bin/save-artifact.sh review findings.json

# Output on success:
# Saved: .nanostack/artifacts/review-2026-03-28T14:22:31Z.json (2.3KB)
# Integrity: sha256:a3f2b8c1d4e5f6...

find-artifact.sh

Locates the most recent artifact for a phase. The search process handles large artifact stores efficiently:

Store directory
  │
  ├─ 1. List files  → ls the store path, filter by phase prefix.
  │                    Only files matching {phase}-*.json.
  │
  ├─ 2. Filter age  → Exclude artifacts older than --max-age (default: 30d).
  │                    Prevents stale context from previous sprints.
  │
  ├─ 3. Pre-filter  → Match --project flag against filename or content.
  │                    Skips artifacts from other projects.
  │
  ├─ 4. Validate    → jq check: is it valid JSON with an integrity field?
  │                    Skips corrupted files silently.
  │
  ├─ 5. Sort        → Sort by timestamp field, descending.
  │
  └─ 6. Return      → Output the path to the most recent match.

Usage:

# Find the latest review artifact
bin/find-artifact.sh --phase review

# Find with project scope
bin/find-artifact.sh --phase review --project nanostack-site

# Find and verify integrity
bin/find-artifact.sh --phase review --verify
# Output: .nanostack/artifacts/review-2026-03-28T14:22:31Z.json (verified)

# If integrity check fails:
# WARNING: integrity mismatch for review-2026-03-28T14:22:31Z.json
# Expected: sha256:a3f2b8c1...
# Got:      sha256:7e9d1a4b...

find-solution.sh

Searches the know-how store for previously documented solutions. Unlike find-artifact.sh, which returns the most recent match, find-solution.sh ranks results by relevance using a scoring formula:

Ranked by:
  severity      critical=4, high=3, medium=2, low=1
  tag matches   +1 per matching word
  recency       +1 if under 30 days old
  staleness     -3 if all referenced files deleted, -1 if some deleted

Usage:

# Find solutions for race conditions
bin/find-solution.sh --type "race-condition"

# Find with tag filtering
bin/find-solution.sh --type "race-condition" --tag "concurrency" --tag "locks"

# Output (ranked):
# 1. [score:12] Race condition in sprint lock acquisition (2026-03-25)
#    .nanostack/know-how/solutions/sprint-lock-race.json
# 2. [score:8]  Database connection pool exhaustion (2026-03-10)
#    .nanostack/know-how/solutions/db-pool-race.json

Secret scanning

Before any artifact is written, save-artifact.shscans every string value for known secret patterns. Matches are redacted in place — the first 8 characters are preserved for debugging, the rest is replaced with [REDACTED].

Pattern              Example match               Redacted output
─────────────────────────────────────────────────────────────────
sk_live_             sk_live_4eC39HqLyjWD...     sk_live_[REDACTED]
sk_test_             sk_test_BQokikJO...         sk_test_[REDACTED]
AKIA                 AKIAIOSFODNN7EXAMPLE        AKIAIOOS[REDACTED]
ghp_                 ghp_xxxxxxxxxxxx...         ghp_xxxx[REDACTED]
xoxb-                xoxb-1234-5678-abcdef       xoxb-123[REDACTED]
sk-ant-              sk-ant-api03-xxxxx...       sk-ant-a[REDACTED]
-----BEGIN.*KEY      -----BEGIN RSA PRIVATE KEY  [KEY_REDACTED]
passwords*[:=]      password: hunter2            password: [REDACTED]

The scan runs on every value in the JSON tree, including nested objects and arrays. If a secret is found, the artifact is still saved (with the redaction), and a warning is printed to stderr:

WARNING: secret pattern detected in artifact (field: config.api_key)
  Pattern: sk_live_
  Redacted in output. Original value was NOT written to disk.

The secret scanner is not configurable per skill. It runs on every artifact, every time, with no opt-out. If you need to store a value that looks like a secret but is not one, wrap it in a safe: prefix and the scanner will skip it.

PreviousArchitectureNextHooks