You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Worker: Sidekiq standalone (./worker) - API-only communication
Business: Git submodule (./extensions/business) - proprietary features (billing, BaaS, reseller, AI publisher)
System: Git submodule (./extensions/system) - node lifecycle, module CRUD, fleet autonomy, on-node Go agent, initramfs, CLI. Public on GitHub (MIT) at nodealchemy/powernode-system, private on Gitea. Mounted as a submodule of this repo since 2026-05-02.
Database: PostgreSQL with native UUID schema
Payments: Stripe, PayPal with PCI compliance (business only)
Project Status: See docs/TODO.md (auto-generated from shared knowledge — do not edit manually)
Core Models
Account → User (many), Subscription (one)
Subscription → Plan, Payments, Invoices
User → Roles, Permissions, Invitations
Specialists
Use platform.discover_skills with a task description to find the right specialist capability. Fallback: MCP_CONFIGURATION.md.
Staged commits: Group changes into logical commits by concern (models, services, controllers, frontend, tests, config) — never one monolithic commit
Business Submodule (./extensions/business)
Separate git repo at extensions/business/ — has its own branch, commits, and a private upstream (added manually by maintainers with access; not committed to public repo)
Always check both repos: git status in root AND git -C extensions/business status — changes in extensions/business/ are invisible to the parent repo's git status
Commit order: Commit inside extensions/business/ first, then update the submodule pointer in the parent repo
Path aliases: Business frontend uses @business/ for intra-business imports, @/ for core shared imports
Core mode: When business submodule is absent, the app runs as single-user self-hosted (all features unlocked, no billing/SaaS)
Feature gating: Shared::FeatureGateService.business_loaded? (backend), __BUSINESS__ build flag (frontend), businessOnly: true on nav items
Permission-Based Access Control (CRITICAL)
Frontend MUST use permissions ONLY - NEVER roles for access control
Backend: Use current_user.has_permission?('name') - NEVER permissions.include?() (returns objects)
Frontend Patterns
Pattern
Rule
Colors
Theme classes only: bg-theme-*, text-theme-*
Navigation
Flat structure - no submenus
Actions
ALL in PageContainer - none in page content
State
Global notifications only - no local success/error
Imports
Path aliases for cross-feature: @/shared/, @/features/
Logging
No console.log in production — use import { logger } from '@/shared/utils/logger' instead
Types
No any - proper TypeScript types required
Backend Patterns
Pattern
Rule
Controllers
Api::V1 namespace, inherit ApplicationController
Responses
MANDATORY: render_success(), render_error()
Worker Jobs
Inherit BaseJob, use execute() method, API-only
Ruby Files
# frozen_string_literal: true pragma required
Logging
Rails.logger - no puts/print
Migrations
t.references automatically creates an index — NEVER use add_index for reference columns. Customize via the declaration itself: t.references :account, index: { unique: true }
Namespaces
ALL namespaced models MUST use :: separator in class_name: — e.g., Ai::AgentTeam not AiAgentTeam, Devops::Pipeline not DevopsPipeline, BaaS::Tenant not BaaSTenant
Seeds
After modifying seeds, run cd server && rails db:seed and verify completion
Associations
Always pair class_name: with foreign_key: — e.g. belongs_to :provider, class_name: "Ai::Provider", foreign_key: "ai_provider_id"
Foreign Keys
Namespaced FK prefixes: Ai:: → ai_ (ai_agent_id), Devops:: → devops_ (devops_pipeline_id), BaaS:: → baas_ (baas_customer_id). Others: use explicit FK or omit if unambiguous
JSON Columns
Always use lambda defaults: attribute :config, :json, default: -> { {} } — never default: {}
Controller Size
Controllers MUST stay under 300 lines — extract query logic to services, serialization to concerns
Eager Loading
Always use .includes() when iterating associations — never bare .all followed by .map/.each accessing relations
Webhook Receivers
Inbound webhooks MUST return 200/202 on processing errors — NEVER 500 (causes provider retry storms)
Cryptographic Material Safety (ABSOLUTE RULES)
Rule
Details
No key output
NEVER output, log, display, echo, or transmit private keys, API secrets, seed phrases, mnemonics, or signing material in any form
No keys in code
NEVER store keys, secrets, or credentials in source code files, scripts, configs, environment files, or documentation
No CLI key generation
NEVER generate private keys via CLI commands (rails runner, rake, irb) where they could appear in shell history
Vault-only storage
ALL key generation MUST happen inside Vault or WalletKeyService (which stores directly to Vault)
Audit all key ops
ALL key operations (generate, import, revoke, sign) MUST be logged to Trading::AuditLog
No key arguments in logs
NEVER pass private keys as function arguments that could appear in logs, error messages, or exception traces
Guide, don't handle
When assisting with wallet setup, guide the user through the UI/API — never handle key material directly
Design Principles
Principle
Rule
Reuse First
platform.discover_skills + platform.search_knowledge + platform.code_semantic_search before proposing anything new — never standalone/greenfield when infrastructure exists
Quality Gates
Run cd frontend && npx tsc --noEmit after TS changes, verify Ruby syntax after .rb changes
Verify Seeds
After seed modifications: cd server && rails db:seed — watch for association/validation errors
Stop & Ask
HARD RULE: After 3 failed attempts at the same fix, STOP immediately and ask the user. Do NOT try a 4th approach, do NOT continue iterating, do NOT try workarounds. Present what you tried and ask for guidance
Audit Sessions
When asked to audit/review/analyze code, save findings to docs/ and do NOT implement changes. Audit = report only, unless the user explicitly says to fix
Verify Changes
Ruby: syntax check + related spec. TypeScript: tsc --noEmit. Migrations: rails db:migrate:status. Seeds: rails db:seed. Use /verify for targeted checks
Verify CWD
Before git operations on submodules, always git rev-parse --show-toplevel to confirm you're in the right repo
Completion Gate
Before reporting work as done, run /verify on changed files. Never mark a task complete with unverified changes
Dead Reference Cleanup
After deleting any file, grep -r for all import/require references to it across the codebase and remove them before committing
Plan Before Multi-File
Changes touching 3+ files: outline which files will change and data flow direction, then wait for user approval before writing code. Single-file fixes can proceed directly
Parallel Investigation
When debugging spans backend + frontend or 3+ services, spawn parallel sub-agents: one per layer/service. Merge findings before proposing a fix — never serialize investigation across layers
Architecture Principles
Principle
Rule
Pull, Never Push
Downstream managers always pull from upstream sources — upstream services NEVER push to downstream. When unsure about data flow direction, ask before implementing
Extension Isolation
Each extension (extensions/*) is self-contained. Extensions depend on core, core NEVER depends on extensions
Service Boundaries
Cross-namespace communication goes through service interfaces, never direct model access across namespaces
Bulk Operation Safety
Rule
Details
State the count
Before ANY bulk operation (approve, reject, delete, update), always state the exact count: "This will affect N items"
Confirmation threshold
Operations affecting more than 5 items require explicit user confirmation
Show samples
For bulk operations, show the first 3 and last 1 items for verification
Never batch-approve
Training decisions, permission grants, and financial operations MUST be reviewed individually
System and supply-chain extensions are publicly mirrored on GitHub — .gitmodules advertises https://github.com/nodealchemy/powernode-system.git and https://github.com/nodealchemy/powernode-supply-chain.git. Maintainer's local checkout has origin = the public GitHub mirror and ipnode = the private upstream (added manually). Push to both remotes on every release. Do NOT run git submodule sync on these submodules — it would overwrite local config and drop the private upstream remote.
Business and trading extensions are not committed to the public repo (gitignored in the parent's tree; not present in .gitmodules). Maintainers with access add them locally via git submodule add <private-url> extensions/business (and similar for trading); their commits go to the private upstream only and never appear in public clones.
CWD verification: Before EVERY git add/git commit, run git rev-parse --show-toplevel and verify it matches the intended repo
Never commit extension files from parent: Files under extensions/*/ MUST be committed from within the submodule. Running git add extensions/trading/... from parent only stages a pointer change
Commit order: Commit inside each submodule FIRST, then update pointers in parent
Terminology
Term
Meaning
Don't Confuse With
server/
Rails app directory on disk
Not "backend directory"
powernode-backend
Systemd service name (powernode-backend@default)
Not "server service" or "rails service"
worker/
Standalone Sidekiq app directory
Not "job runner"
powernode-worker
Systemd service name (powernode-worker@default)
Not "sidekiq service"
Service Management
# Systemd services (requires initial install: sudo scripts/systemd/powernode-installer.sh install)
sudo systemctl start powernode.target # Start all services
sudo systemctl stop powernode.target # Stop all services
sudo systemctl restart powernode-backend@default # Restart individual service
sudo scripts/systemd/powernode-installer.sh status # Show all service status
journalctl -u powernode-backend@default -f # Tail service logs
NEVER use manual commands (rails server, sidekiq, npm start)
Service Operations Reference
Service
Unit Name
Port
Restart Behavior
Rails API
powernode-backend@default
3000
SIGUSR2 reload (~30ms) via scripts/reload-backend.sh. Auto-reloaded by Stop hook after .rb edits
Sidekiq
powernode-worker@default
—
Full restart (~28s drain). Wait 30s before checking status — "deactivating" is normal during drain
Worker HTTP API
powernode-worker-web@default
4567
If port 4567 refused, restart THIS service, not powernode-worker
Frontend
powernode-frontend@default
5173
Full restart
Stuck worker: If worker is draining >30s, use sudo systemctl stop powernode-worker@default && sudo systemctl start powernode-worker@default (stop+start, not restart)
Never restart worker multiple times in quick succession — batch code changes, ONE restart at end
After restart: Verify with sudo scripts/systemd/powernode-installer.sh status
Test Execution
RSpec:
cd server && bundle exec rspec --format progress # Full suitecd server && bundle exec rspec spec/path_spec.rb # Single file
Frontend tests - always use CI=true:
cd frontend && CI=true npm test
Multi-Agent Test Rules
Uses DatabaseCleaner with :deletion strategy — avoids TRUNCATE deadlocks between concurrent processes.
Do NOT run multiple single-process rspec instances simultaneously on the same database.
Frontend tests (CI=true npm test) and TypeScript checks (npx tsc --noEmit) are always safe to run concurrently.
Worker Architecture (CRITICAL)
The server (server/) is a Rails API — it does NOT run Sidekiq
The worker (worker/) is a standalone Sidekiq process — it communicates with server via HTTP API only
NEVER create job classes in server/app/jobs/ — jobs belong in worker/app/jobs/
NEVER add Sidekiq gems to server/Gemfile
NEVER modify worker/ files when fixing server issues
Test Patterns Reference
Pattern
Rule
Factories
spec/factories/ — use existing factories with traits (:active, :paused, :archived). AI factories in spec/factories/ai/
User Setup
user_with_permissions('perm.name') from permission_test_helpers.rb — never create users manually
Auth Headers
auth_headers_for(user) returns { Authorization: Bearer ... } — use in all request specs
The Powernode MCP server (platform.* tools) is the primary knowledge source. File scanning is the fallback. MCP queries are NOT optional — they are mandatory protocol steps.
SESSION START Protocol (MANDATORY — every session)
Run platform.knowledge_health — establish baseline, identify stale/conflicting knowledge
Run platform.learning_metrics — check active learnings count, recent contributions
If stale_count > 0 or conflicts detected, note them for resolution during the session
Run platform.code_index_status with repository_id: "powernode-platform" — check codebase index freshness and stale file count
BEFORE EVERY CODE CHANGE (MANDATORY)
Search existing knowledge for the area being modified — not optional, not "when convenient":
platform.query_learnings — established patterns, anti-patterns, failure modes for this area
platform.search_knowledge — procedures, code snippets, reference material
Self-check: "Did I create learnings for the critical findings in this task?" If no, do it now.
Skip Contributions For
Trivial fixes (typos, simple renames, formatting)
Speculative or unverified analysis
Knowledge that already exists in MCP (always search first)
MCP Tool Invocation
Claude Code invokes platform.* tools directly via the streamable-http MCP server registered in .claude/settings.json (powernode entry pointing at http://localhost:3000/api/v1/mcp/message). No external daemon, no helper scripts — just call the tool by name.
MCP Tool Catalog
All platform.* tools organized by development task. Full parameter docs: MCP_TOOL_CATALOG.md.
Discovery & Context (10 tools)
Tool
Description
search_knowledge
Semantic search across shared knowledge entries
query_learnings
Query compound learnings by category, status, or text
search_knowledge_graph
Semantic search over knowledge graph nodes
reason_knowledge_graph
Multi-hop reasoning across graph relationships
discover_skills
Find reusable skills matching a task description
get_skill_context
Get full execution context for a specific skill
search_memory
Search agent working/shared memory pools
search_documents
Search RAG document chunks by query
query_knowledge_base
Query a specific knowledge base with RAG
get_api_reference
Look up API endpoint contracts and schemas
Knowledge Contribution (7 tools)
Tool
Description
create_learning
Create a compound learning (categories: pattern, best_practice, discovery, failure_mode)
create_knowledge
Create a shared knowledge entry (content_types: procedure, reference, guide)
update_knowledge
Update an existing shared knowledge entry
promote_knowledge
Promote knowledge for cross-team visibility
extract_to_knowledge_graph
Extract entities and relationships to the knowledge graph
create_skill
Register a reusable skill with execution context
update_skill
Update an existing skill definition
Quality & Reinforcement (9 tools)
Tool
Description
verify_learning
Verify a learning as accurate (boosts confidence)
dispute_learning
Dispute an inaccurate learning with reason
resolve_contradiction
Pick a winner between two conflicting learnings
rate_knowledge
Rate shared knowledge quality (1-5 scale)
reinforce_learning
Reinforce a learning that was used successfully
knowledge_health
Cross-system health report (learnings + knowledge + graph)
learning_metrics
Compound learning statistics and trends
skill_health
Skill system health and conflict report
skill_metrics
Skill usage statistics and effectiveness
Agent Management (5 tools)
Tool
Description
create_agent
Create a new AI agent with provider and model config
list_agents
List agents (filterable by status, provider)
get_agent
Get full agent details including trust score
update_agent
Update agent configuration
execute_agent
Execute an agent with a prompt and optional tools
Team Management (6 tools)
Tool
Description
create_team
Create an agent team with composition rules
list_teams
List teams (filterable by status)
get_team
Get team details including members and roles
update_team
Update team configuration
add_team_member
Add an agent to a team with a role
execute_team
Execute a team task with orchestration
Knowledge Graph Exploration (7 tools)
Tool
Description
search_knowledge_graph
Semantic search over graph nodes
reason_knowledge_graph
Multi-hop reasoning across relationships
get_graph_node
Get a specific node with its relationships
list_graph_nodes
List graph nodes (filterable by type, label)
get_graph_neighbors
Get connected nodes within N hops
graph_statistics
Graph-wide statistics (node/edge counts, density)
get_subgraph
Extract a subgraph around a focal node
Memory Management (6 tools)
Tool
Description
write_shared_memory
Write to a shared memory pool (key-value with TTL)
read_shared_memory
Read from a shared memory pool by key
search_memory
Semantic search across memory entries
consolidate_memory
Trigger memory tier consolidation (STM→LTM)
memory_stats
Memory usage statistics per tier
list_pools
List available memory pools for an agent/team
RAG & Documents (7 tools)
Tool
Description
query_knowledge_base
Query a knowledge base using RAG retrieval
list_knowledge_bases
List available knowledge bases
create_knowledge_base
Create a new knowledge base
add_document
Add a document to a knowledge base
process_document
Trigger document chunking and embedding
search_documents
Search document chunks by semantic query
delete_document
Remove a document from a knowledge base
Content Management (8 tools)
Tool
Description
list_kb_articles
List knowledge base articles
get_kb_article
Get article content and metadata
create_kb_article
Create a new KB article
update_kb_article
Update an existing KB article
list_pages
List content pages
get_page
Get page content and metadata
create_page
Create a new content page
update_page
Update an existing content page
Skill Administration (4 tools)
Tool
Description
list_skills
List skills with pagination and filters
get_skill
Get full skill definition and execution context
delete_skill
Remove a skill
toggle_skill
Enable or disable a skill
AI Autonomy & Safety (16 tools)
Tool
Description
emergency_halt
Emergency halt ALL AI activity (kill switch)
emergency_resume
Resume AI activity after emergency halt
kill_switch_status
Check current kill switch state
create_agent_goal
Create a goal for an agent (self or managed)
list_agent_goals
List an agent's goals (introspection)
update_agent_goal
Update goal progress or status
agent_introspect
View own execution history, trust score, performance, and budget
propose_feature
Create a feature suggestion for human review
send_proactive_notification
Notify users about detected issues or suggestions
discover_claude_sessions
Find active Claude Code MCP client sessions
request_code_change
Request code changes via workspace message
create_proposal
Formally propose a change for human review
escalate
Structured escalation when stuck or encountering issues
request_feedback
Request user feedback on completed work
report_issue
Report a detected platform issue
Codebase Intelligence (14 tools)
Tool
Description
code_context_tree
AST-based structural tree with file headers and symbol ranges (depth-pruned)
code_file_skeleton
Function signatures, class methods, type definitions with line ranges (no bodies)
code_semantic_search
Semantic search over code symbols using embeddings — finds code by meaning
code_identifier_search
Search identifiers (functions, classes, variables) by name with usage counts
code_semantic_navigate
Browse codebase by meaning using semantic clustering with labeled groups
code_feature_hub
Obsidian-style feature navigation from markdown [[wikilinks]]
code_blast_radius
Trace every file and line where a symbol is imported or used — impact analysis
code_static_analysis
Run native linters/compilers (RuboCop, TypeScript, ESLint) with structured output
code_index_status
Codebase index statistics: files indexed, symbols, staleness, embedding coverage
code_upsert_node
Create/update a code-aware knowledge graph node with auto-embedding
code_create_relation
Create typed edges between code nodes (imports, calls, inherits, etc.)
code_search_graph
Search code graph with optional multi-hop traversal
code_prune_stale
Find/archive nodes for files that no longer exist (dry_run supported)
Before starting work: Run platform.knowledge_health if last check was >24h ago
When encountering bugs: Always search platform.query_learnings for existing fix — if found, reinforce_learning; if not, fix and create_learning
When removing stale code: Create a learning documenting what was removed and why
When fixing documentation: Update platform.update_knowledge to correct the source entry
Tool Evolution
All platform.* tools are defined in server/app/services/ai/tools/platform_api_tool_registry.rb.
When tools are added/modified, run cd server && rails mcp:generate_tool_catalog to regenerate docs/platform/MCP_TOOL_CATALOG.md.
When MCP knowledge is updated significantly, run cd server && rails mcp:sync_docs to regenerate fallback docs in docs/platform/knowledge/.
Knowledge sync runs automatically daily at 5:30 AM UTC via AiKnowledgeDocSyncJob.
Adding a New Tool
Create tool class in server/app/services/ai/tools/
Add action→class mapping to PlatformApiToolRegistry::TOOLS
Add action_definitions with descriptions and parameter schemas
Run rails mcp:generate_tool_catalog → updates docs/platform/MCP_TOOL_CATALOG.md
Update relevant CLAUDE.md component file(s) with the new tool
Create learning: platform.create_learning category: pattern documenting the new tool
Deprecating a Tool
Add deprecation notice to action_definitions description
Create learning: platform.create_learning category: best_practice documenting the replacement