Add cross-project pattern registry for retrieval-augmented generalization

- Create patterns/ directory with README, manifest, and 10 initial patterns
  covering Ollama JSON fallback, API escaping, deprecation, PTY auth,
  queue-poll, LLM-as-parser, credential rotation, reverse proxy binding,
  human approval gates, and transient retry.
- Wire pattern loading into architecture/pipeline.js based on task tags.
- Update architecture/orchestrator.js to load patterns and surface them in
  the system prompt.
- Update MEMORY.md, ARCHITECTURE.md, and CONTEXT.md to document the registry
  and record the decision.
This commit is contained in:
JC Beasley
2026-08-06 12:46:09 -07:00
parent d8989f9371
commit 0bd719ab91
17 changed files with 676 additions and 32 deletions
+70
View File
@@ -0,0 +1,70 @@
# Cross-Project Technical Pattern Registry
## Purpose
This registry captures recurring technical lessons, workarounds, design choices, and failure modes that appear across Beawit's applications and automation workflows. It exists so agents can recognize when a new task is an instance of a known pattern and apply proven countermeasures instead of rediscovering the problem.
This is the **generalization layer** of the agent continual-learning system:
- **Plasticity**: new patterns are added as they are discovered.
- **Stability**: old patterns are versioned and never silently overwritten.
- **Generalization**: patterns are retrieved by symptom, cause, or affected domain and injected into task context.
## Registry Structure
```
patterns/
├── README.md # This file
├── patterns.json # Machine-readable manifest
├── ollama-structured-output-fallback.md
├── json-escaping-downstream-api.md
├── api-version-deprecation.md
├── pty-device-code-auth.md
├── queue-poll-async-job.md
├── llm-as-parser-fallback.md
├── credential-rotation-recovery.md
├── reverse-proxy-container-binding.md
├── human-approval-risky-publish.md
└── transient-failure-retry.md
```
## Pattern File Template
Every `.md` pattern uses the same sections:
```markdown
# Pattern: <Short Name>
## Symptom
What the agent or user sees when the pattern is active.
## Affected Projects
List of known projects/workflows where this pattern has occurred.
## Root Cause
Why it happens.
## Standard Fix
The proven workaround, safety net, or design choice.
## When to Apply
Trigger conditions for applying this pattern to a new task.
## Verification
How to confirm the fix actually worked.
## Related Patterns
Links to other patterns that often appear together.
```
## How Patterns Are Used
1. **Manual reference** — read the registry before designing a new integration or workflow.
2. **Automatic retrieval**`architecture/pipeline.js` loads relevant patterns into the context packet based on keyword matching against the task input.
3. **Skill/worfklow design** — when a new workaround is applied, propose a new pattern entry if the underlying shape is reusable.
## Adding or Updating a Pattern
1. Create or edit the `.md` file.
2. Update `patterns.json` with id, tags, related patterns, and affected projects.
3. Run `node architecture/pipeline.js "sample query"` to verify the pattern is retrievable.
4. Update `MEMORY.md` Cross-Project Patterns if the pattern is stable and reusable.
+29
View File
@@ -0,0 +1,29 @@
# Pattern: API Version Deprecation
## Symptom
An integration that worked yesterday starts returning 400/401/404 or generic errors. Vendor documentation mentions an older API version is deprecated or sunset. Calls using the old version silently stop working or return migration messages.
## Affected Projects
- LinkedIn content automation (LinkedIn REST API version deprecation)
## Root Cause
External SaaS APIs version their endpoints and periodically retire old versions. Hard-coded version strings in workflows or apps become liabilities when the vendor changes the supported window.
## Standard Fix
1. Record the API version in use at design time, plus where to check for deprecation notices (vendor developer portal, changelog, email alerts).
2. Centralize API version strings in environment variables or config, not scattered through code.
3. Subscribe to vendor developer changelogs or status pages.
4. Plan version migration as a tracked task rather than an emergency fix.
5. Add a lightweight health check that verifies the integration still responds with expected schema/version fields.
## When to Apply
- Every new external API integration.
- Any existing integration that has no documented API version or deprecation monitoring.
## Verification
- Vendor docs show the version is current and supported.
- Health check returns expected version/schema fields.
- A deprecation monitoring source is identified and checked.
## Related Patterns
- `credential-rotation-recovery`
+31
View File
@@ -0,0 +1,31 @@
# Pattern: Credential Rotation and External Service Breakage
## Symptom
An integration that previously worked starts failing with authentication errors, 401/403 responses, or "invalid token" messages. No code has changed. The root cause is an expired or rotated API key, AppRole secret, OAuth token, or vault credential.
## Affected Projects
- n8n workflows using AppRole or API keys
- NocoDB token-based integrations
- Any service using HashiCorp Vault AppRole authentication
## Root Cause
Credentials have finite lifetimes or rotation policies. If the integration has no renewal path and the credential is stored in only one place, expiry causes immediate breakage that looks like a code problem.
## Standard Fix
1. Store credentials in Vault, not in code, config files, or workflow nodes.
2. Document credential lifetime and rotation procedure in the project RUNBOOK.
3. Add health checks that verify credential validity without performing risky operations.
4. Where possible, implement token refresh or AppRole re-login rather than relying on static long-lived tokens.
5. Alert before expiry, not after.
## When to Apply
- Every new integration that uses an API key, token, password, or secret.
- Any existing integration that has no documented credential source or rotation plan.
## Verification
- Health check passes using the stored credential.
- Rotation procedure has been tested end-to-end.
- No secrets are committed to version control.
## Related Patterns
- `api-version-deprecation`
+33
View File
@@ -0,0 +1,33 @@
# Pattern: Human Approval Gate for Risky Publish Operations
## Symptom
An automation publishes or sends content on behalf of the organization (LinkedIn post, client email, newsletter). A mistake in generated content, targeting, or timing causes embarrassment, compliance risk, or customer impact. Once sent, it cannot be recalled.
## Affected Projects
- LinkedIn content automation
- Cyber Tips Newsletter pipeline
- Email inbox triage agent (if it sends replies)
- Monthly IT newsletter generator
## Root Cause
LLM-generated content is probabilistic and may contain hallucinations, wrong tone, outdated facts, or malformed formatting. Fully automated publishing removes the human sanity check.
## Standard Fix
1. Generate the draft and present it for human review before any publish/send action.
2. Separate "draft" and "publish" stages in the workflow.
3. Require explicit confirmation (button click, message reaction, approval field) for the publish step.
4. Log who approved what and when.
5. Provide an easy cancellation path before the deadline.
## When to Apply
- Any workflow that sends client-facing communications.
- Any workflow that posts to public or branded channels.
- Any workflow where content cannot be retracted after execution.
## Verification
- Draft stage produces reviewable content.
- Publish step does not execute without explicit approval.
- Audit log records approver, timestamp, and content hash/summary.
## Related Patterns
- None yet.
+32
View File
@@ -0,0 +1,32 @@
# Pattern: JSON Escaping for Downstream APIs
## Symptom
An n8n workflow passes LLM-generated text into a downstream API call, and the request fails with a JSON parse error, malformed payload, or unexpected truncation. The generated text contains quotes, newlines, backslashes, emojis, or control characters that break JSON encoding.
## Affected Projects
- LinkedIn content automation (LinkedIn REST API posts)
- AI video generation pipeline (ComfyUI / JSON2Video payloads)
- Any n8n workflow that injects LLM output into an HTTP Request node body
## Root Cause
LLMs produce human-readable text; downstream APIs consume machine-readable JSON. Naive string concatenation or weak JSON serialization allows unescaped characters to corrupt the payload. The failure often appears at the receiving API, making root-cause diagnosis slower.
## Standard Fix
1. Treat LLM output as untrusted string data.
2. Always serialize it through a proper JSON encoder (`JSON.stringify` in JS, `json.dumps` in Python) before embedding in a payload.
3. If building a payload string manually, escape quotes, backslashes, newlines, and control characters; better, avoid manual string building entirely.
4. Add a validation step that parses the final payload with `JSON.parse` before sending.
5. For n8n, prefer expression mapping through structured fields rather than raw body strings.
## When to Apply
- Any new integration where LLM-generated content becomes part of an API request body.
- Any HTTP Request node in n8n that builds a JSON body from expressions containing LLM output.
## Verification
- Test with adversarial LLM output containing quotes, newlines, unicode, and backslashes.
- Confirm the receiving API parses the payload correctly.
- Log payload shape (without secrets) for debugging.
## Related Patterns
- `ollama-structured-output-fallback`
- `llm-as-parser-fallback`
+33
View File
@@ -0,0 +1,33 @@
# Pattern: LLM-as-Parser with Structured Fallback
## Symptom
A workflow asks an LLM to parse, classify, or extract information from unstructured input. Sometimes the output is correct but poorly formatted; sometimes it is wrong or inconsistent. Downstream nodes cannot rely on it without a validation step.
## Affected Projects
- Cyber Tips Newsletter pipeline
- Proxmox VE snapshot summarizer
- Email inbox triage agent
- Monthly IT newsletter generator
## Root Cause
Using an LLM as a parser combines the power of fuzzy reasoning with the fragility of probabilistic output. Without a structured fallback, the pipeline is brittle.
## Standard Fix
1. Ask the LLM for structured output (JSON/schema) when possible.
2. Add a validation layer that checks required fields and value ranges.
3. Add a regex or rule-based extraction fallback for common failure modes.
4. For classification tasks, maintain a small deterministic ruleset for high-confidence cases and use the LLM only for ambiguous cases.
5. Log parse failures to identify when the LLM is drifting.
## When to Apply
- Any workflow where an LLM extracts or classifies data that downstream nodes consume.
- Any pipeline where consistency matters more than creative interpretation.
## Verification
- Test with malformed, ambiguous, and adversarial inputs.
- Confirm downstream nodes receive validated, structured data.
- Review parse-failure logs periodically.
## Related Patterns
- `ollama-structured-output-fallback`
- `json-escaping-downstream-api`
@@ -0,0 +1,35 @@
# Pattern: Ollama Structured Output Fallback
## Symptom
A workflow calls a local Ollama model (e.g., `gemma3:4b`, small quantized models) with a structured-output or JSON schema request, but the returned text is not valid JSON, misses required fields, wraps the JSON in prose, or otherwise fails schema validation.
## Affected Projects
- Cyber Tips Newsletter pipeline
- Proxmox VE snapshot summarizer
- AI video generation pipeline (ComfyUI + WAN 2.1 payloads)
- Forex trading analysis workflow
## Root Cause
Small local instruction-tuned models have weaker schema adherence than frontier APIs. They may produce JSON-like text that does not strictly conform to the requested schema, especially under complex prompts or when asked to combine generation with strict formatting.
## Standard Fix
Add a downstream JavaScript Code node (or equivalent parser) in n8n that:
1. Attempts a strict `JSON.parse()` first.
2. On failure, applies regex-based JSON extraction to pull the first `{...}` or `[...]` block from the text.
3. Optionally sanitizes common issues (trailing commas, unescaped newlines, code fences).
4. Falls back to a safe default or error flag if extraction still fails.
This is a deliberate workaround, not a substitute for fixing the model. Document it as such wherever applied.
## When to Apply
- Any new n8n workflow that uses a local Ollama model for structured extraction, classification, or JSON generation.
- Any integration where the downstream node requires strict JSON and the LLM is under ~8B parameters or known to drift.
## Verification
- Test the fallback with intentionally malformed LLM output.
- Confirm downstream nodes receive valid parsed JSON.
- Log fallback events so model quality can be monitored separately.
## Related Patterns
- `json-escaping-downstream-api`
- `llm-as-parser-fallback`
+138
View File
@@ -0,0 +1,138 @@
{
"version": "2026-08-06",
"description": "Cross-project technical pattern registry for retrieval-augmented generalization",
"patterns": [
{
"id": "ollama-structured-output-fallback",
"name": "Ollama Structured Output Fallback",
"file": "patterns/ollama-structured-output-fallback.md",
"tags": ["ollama", "json", "structured-output", "local-llm", "n8n", "safety-net", "regex"],
"affected_projects": [
"cyber-tips-newsletter",
"proxmox-snapshot-summarizer",
"ai-video-generation",
"forex-trading-analysis"
],
"related_patterns": [
"json-escaping-downstream-api",
"llm-as-parser-fallback"
]
},
{
"id": "json-escaping-downstream-api",
"name": "JSON Escaping for Downstream APIs",
"file": "patterns/json-escaping-downstream-api.md",
"tags": ["json", "escaping", "llm-output", "api-payload", "n8n", "linkedin", "video-generation"],
"affected_projects": [
"linkedin-automation",
"ai-video-generation",
"n8n-general"
],
"related_patterns": [
"ollama-structured-output-fallback",
"llm-as-parser-fallback"
]
},
{
"id": "api-version-deprecation",
"name": "API Version Deprecation",
"file": "patterns/api-version-deprecation.md",
"tags": ["api", "versioning", "deprecation", "integration", "breaking-change", "linkedin"],
"affected_projects": [
"linkedin-automation"
],
"related_patterns": [
"credential-rotation-recovery"
]
},
{
"id": "pty-device-code-auth",
"name": "PTY-Required Device Code Authentication",
"file": "patterns/pty-device-code-auth.md",
"tags": ["powershell", "pty", "device-code", "authentication", "microsoft-graph", "intune-inspector", "pexpect"],
"affected_projects": [
"intune-inspector",
"m365-admin-toolkit"
],
"related_patterns": []
},
{
"id": "queue-poll-async-job",
"name": "Queue-Poll Async Job Pattern",
"file": "patterns/queue-poll-async-job.md",
"tags": ["async", "queue", "poll", "long-running", "comfyui", "ollama", "n8n"],
"affected_projects": [
"ai-video-generation",
"n8n-general"
],
"related_patterns": [
"transient-failure-retry"
]
},
{
"id": "llm-as-parser-fallback",
"name": "LLM-as-Parser with Structured Fallback",
"file": "patterns/llm-as-parser-fallback.md",
"tags": ["llm", "parsing", "structured-output", "fallback", "validation", "regex"],
"affected_projects": [
"cyber-tips-newsletter",
"proxmox-snapshot-summarizer",
"email-inbox-triage",
"monthly-it-newsletter"
],
"related_patterns": [
"ollama-structured-output-fallback",
"json-escaping-downstream-api"
]
},
{
"id": "credential-rotation-recovery",
"name": "Credential Rotation and External Service Breakage",
"file": "patterns/credential-rotation-recovery.md",
"tags": ["credentials", "vault", "rotation", "token", "api-key", "secrets", "approle"],
"affected_projects": [
"n8n-general",
"nocodb",
"vault"
],
"related_patterns": [
"api-version-deprecation"
]
},
{
"id": "reverse-proxy-container-binding",
"name": "Reverse Proxy + Container Port Binding",
"file": "patterns/reverse-proxy-container-binding.md",
"tags": ["reverse-proxy", "nginx-proxy-manager", "docker", "container", "port-binding", "nextcloud"],
"affected_projects": [
"nextcloud-aio"
],
"related_patterns": []
},
{
"id": "human-approval-risky-publish",
"name": "Human Approval Gate for Risky Publish Operations",
"file": "patterns/human-approval-risky-publish.md",
"tags": ["approval", "human-in-the-loop", "publish", "email", "linkedin", "client-facing", "risk"],
"affected_projects": [
"linkedin-automation",
"email-inbox-triage",
"cyber-tips-newsletter"
],
"related_patterns": []
},
{
"id": "transient-failure-retry",
"name": "Transient Failure Retry and Degradation",
"file": "patterns/transient-failure-retry.md",
"tags": ["retry", "backoff", "transient", "ollama", "network", "rate-limit", "queue"],
"affected_projects": [
"n8n-general",
"ollama-general"
],
"related_patterns": [
"queue-poll-async-job"
]
}
]
}
+29
View File
@@ -0,0 +1,29 @@
# Pattern: PTY-Required Device Code Authentication
## Symptom
A web app or automation script shells out to a CLI tool (e.g., PowerShell `Connect-MgGraph -UseDeviceAuthentication`) and hangs. The user never sees the device code or authentication URL needed to complete login. The process appears to do nothing.
## Affected Projects
- Intune Inspector (PowerShell + Microsoft Graph device code auth)
- Microsoft 365 Admin Toolkit (PowerShell + Microsoft Graph)
## Root Cause
Some CLI commands write authentication prompts to the console host rather than stdout. When run via `subprocess.Popen` or equivalent without a pseudo-terminal (PTY), that output is not captured or displayed, so the user cannot complete the interactive step.
## Standard Fix
1. Use a PTY-enabled subprocess library (`pexpect` in Python, `node-pty` in Node.js) so the spawned process believes it has a real terminal.
2. Capture and surface console-host output to the user in real time (device code, URL, instructions).
3. Poll for completion if the process is long-running.
4. Document that this is a workaround for interactive CLI flows that cannot be fully non-interactive.
## When to Apply
- Any integration that spawns a command-line tool requiring interactive authentication.
- Microsoft Graph device-code flows, Azure CLI login prompts, OAuth CLI helpers, or similar tools.
## Verification
- Running the script standalone in a real terminal produces a device code/URL.
- The app captures and displays the same code/URL via PTY.
- Authentication completes and the downstream operation succeeds.
## Related Patterns
- None yet.
+32
View File
@@ -0,0 +1,32 @@
# Pattern: Queue-Poll Async Job Pattern
## Symptom
An operation takes longer than a synchronous HTTP timeout allows (video generation, large LLM generation, batch job). The caller either times out, retries redundantly, or loses track of the job state.
## Affected Projects
- AI video generation pipeline (ComfyUI + WAN 2.1)
- Long-running Ollama generations in n8n
- Any workflow that submits work to a queue and must wait for completion
## Root Cause
The work is genuinely asynchronous, but the integration is designed as if it were synchronous. Without explicit job-state tracking, the system cannot wait, retry, or recover correctly.
## Standard Fix
1. Submit the job and immediately capture a job/prompt ID.
2. Poll a status endpoint on a fixed interval with exponential backoff.
3. Define terminal states (completed, failed, cancelled) and a max poll duration.
4. Store intermediate state so a restart does not lose the job ID.
5. Surface progress to the user if the operation is user-facing.
## When to Apply
- Any integration where the expected duration exceeds a reasonable HTTP timeout (~30-60 seconds).
- Any service that returns a job ID or queue position instead of the final result.
## Verification
- Job submission returns an ID.
- Polling correctly detects completion and failure.
- No duplicate work is triggered by retries.
- Progress/state survives a brief restart of the polling service.
## Related Patterns
- `transient-failure-retry`
@@ -0,0 +1,30 @@
# Pattern: Reverse Proxy + Container Port Binding
## Symptom
A self-hosted Docker service (Nextcloud AIO, ComfyUI, etc.) is deployed behind a reverse proxy such as Nginx Proxy Manager. The service is unreachable, returns 502/504, or binds to the wrong network/interface. Docker network complexity, port mappings, and internal DNS all become debugging obstacles.
## Affected Projects
- Nextcloud AIO on `bve.beawit.net`
- Any future self-hosted service deployed behind Nginx Proxy Manager
## Root Cause
Containerized services often bind to localhost or a Docker-internal IP by default. A reverse proxy running on the host or in another container cannot reach them without explicit port binding and network configuration. NAT, firewall, and Docker bridge behavior add confusion.
## Standard Fix
1. Decide early whether to use host networking (`--network host`) or explicit port mapping with a known internal IP.
2. If using host network, bind the service to `0.0.0.0` on a fixed, documented port and point the reverse proxy to the host IP.
3. If using bridge mode, ensure the reverse proxy can reach the container by name or fixed IP.
4. Document the chosen network topology in the RUNBOOK.
5. Verify reachability from the reverse proxy host before declaring the deployment done.
## When to Apply
- Every new containerized service that will be exposed through a reverse proxy.
- Any existing service with intermittent 502/504 or binding issues.
## Verification
- Reverse proxy can curl the backend service directly.
- External HTTPS access returns expected responses.
- Configuration survives container restart.
## Related Patterns
- None yet.
+31
View File
@@ -0,0 +1,31 @@
# Pattern: Transient Failure Retry and Degradation
## Symptom
A workflow or agent fails intermittently due to temporary conditions: Ollama model not loaded yet, network blip, rate limit, dependent service restart. A simple rerun often succeeds, but the failure creates noise, lost state, or unnecessary alerts.
## Affected Projects
- n8n workflows calling Ollama
- Queue-poll integrations
- Any service with external dependencies
## Root Cause
Distributed services are not always available at the moment a caller needs them. Treating every transient failure as a hard error produces false alarms and breaks pipelines that should recover automatically.
## Standard Fix
1. Classify failures as retryable (network, timeout, 429, 503) or non-retryable (400, 401, schema error).
2. Apply retry with exponential backoff and jitter for retryable failures.
3. Set a maximum retry count and a dead-letter/escalation path for persistent failures.
4. Degrade gracefully if a non-critical dependency fails (e.g., return partial results, skip enrichment).
5. Distinguish retry events from terminal failures in logs and alerts.
## When to Apply
- Any integration that calls an external service over the network.
- Any workflow that has experienced at least one "worked on retry" incident.
## Verification
- Simulated transient failure triggers retry and eventual success.
- Non-retryable failure escalates immediately without wasteful retries.
- Logs clearly show retry count, backoff, and final disposition.
## Related Patterns
- `queue-poll-async-job`