Block Schema Reference

Block v2 — Universal execution unit for the Process Factory Engine

1. Block v2 JSON Schema (Formal Definition)

The Block v2 is the universal execution unit. Every skill in the pipeline is wrapped in a Block that declares its dependencies, outputs, execution constraints, and lifecycle. The schema below is the complete formal definition.

JSON Schema (draft-07)
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Block v2",
  "description": "Universal execution unit for the Process Factory Engine",
  "type": "object",
  "required": ["id", "name", "layer", "type", "skill", "trigger", "inputs", "outputs", "execution", "lifecycle"],
  "properties": {
    "id": {
      "type": "string",
      "description": "Unique block identifier, typically matches skill name"
    },
    "name": {
      "type": "string",
      "description": "Human-readable display name"
    },
    "layer": {
      "type": "string",
      "enum": ["L0", "L0.25", "L0.5", "L1", "L2", "L2.5", "L3", "L3.5", "L4"],
      "description": "Execution layer in the pipeline"
    },
    "type": {
      "type": "string",
      "enum": ["extract", "validate", "build", "orchestrate", "research", "ingest"],
      "description": "Block functional category"
    },
    "skill": {
      "type": "string",
      "description": "Maps to SKILL.md file in skills directory"
    },
    "model": {
      "type": ["string", "null"],
      "enum": ["opus", "sonnet", null],
      "description": "Model override, null inherits from run config"
    },
    "timeout": {
      "type": "number",
      "default": 300000,
      "description": "Execution timeout in milliseconds"
    },
    "runtime": {
      "type": "string",
      "enum": ["forge", "claude-cli", "mastery-api", "nowpage"],
      "description": "Execution runtime environment"
    },
    "trigger": {
      "type": "object",
      "required": ["type"],
      "properties": {
        "type": { "type": "string", "enum": ["dependency", "cron", "webhook", "event", "manual"] },
        "cron": { "type": ["string", "null"] },
        "event": { "type": ["string", "null"] },
        "webhook": { "type": ["string", "null"] }
      }
    },
    "inputs": {
      "type": "object",
      "properties": {
        "depends": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "block": { "type": "string" },
              "key": { "type": "string" }
            }
          }
        },
        "files": { "type": "array", "items": { "type": "string" } },
        "env": { "type": "array", "items": { "type": "string" } },
        "config": { "type": "object" }
      }
    },
    "outputs": {
      "type": "object",
      "properties": {
        "artifacts": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "key": { "type": "string" },
              "path": { "type": "string" },
              "format": { "type": "string" }
            }
          }
        },
        "metrics": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "key": { "type": "string" },
              "type": { "type": "string" }
            }
          }
        },
        "publish": {
          "type": ["array", "null"],
          "items": {
            "type": "object",
            "properties": {
              "domain": { "type": "string" },
              "slug": { "type": "string" }
            }
          }
        }
      }
    },
    "execution": {
      "type": "object",
      "properties": {
        "parallel_group": { "type": ["string", "null"] },
        "human_gate": {
          "type": "string",
          "enum": ["before", "after", "none"],
          "default": "none"
        },
        "threshold": {
          "type": ["object", "null"],
          "properties": {
            "metric": { "type": "string" },
            "min": { "type": "number" }
          }
        },
        "retryable": { "type": "boolean", "default": true },
        "max_retries": { "type": "number", "default": 2 }
      }
    },
    "lifecycle": {
      "type": "object",
      "required": ["mode"],
      "properties": {
        "mode": {
          "type": "string",
          "enum": ["one-shot", "daemon", "on-demand"]
        }
      }
    },
    "scope": {
      "type": "object",
      "properties": {
        "gate": { "type": ["number", "null"], "enum": [1, 2, 3, 4, null] },
        "run_params": { "type": "object" }
      }
    },
    "lens": {
      "type": "object",
      "properties": {
        "perspective": { "type": ["string", "null"] },
        "aggregates": { "type": ["array", "null"], "items": { "type": "string" } },
        "feedback_loop": { "type": "boolean", "default": false }
      }
    },
    "record_state": {
      "type": "object",
      "properties": {
        "track_per": { "type": ["string", "null"] },
        "states": { "type": "array", "items": { "type": "string" } }
      }
    },
    "state": {
      "type": "object",
      "description": "Runtime state managed by engine, not set in config",
      "properties": {
        "status": {
          "type": "string",
          "enum": ["pending", "ready", "running", "done", "failed", "blocked", "waiting"],
          "default": "pending"
        },
        "started_at": { "type": ["string", "null"], "format": "date-time" },
        "ended_at": { "type": ["string", "null"], "format": "date-time" },
        "score": { "type": ["number", "null"] },
        "error": { "type": ["string", "null"] },
        "attempts": { "type": "number", "default": 0 }
      }
    }
  }
}
Required Fields

A block must include: id, name, layer, type, skill, trigger, inputs, outputs, execution, and lifecycle. All other top-level properties are optional and default to null/empty.

State is Runtime-Only

The state property is managed entirely by the engine at runtime. Never set it in block config files. The engine initializes all blocks with status: "pending" at run start.

2. Example Blocks

Four complete blocks demonstrating different patterns: root-level research, framework extraction with human gate, parallel extraction, and validation with thresholds.

Example 1: deep-research (L0, research, parallel group)

Pattern: Root node with no dependencies. Runs in the L0-recon parallel group alongside expert-recon and masterybook-sync. Uses Perplexity API via env var. Publishes intel report to NowPage.
JSON — deep-research block
{
  "id": "deep-research",
  "name": "Deep Research",
  "layer": "L0",
  "type": "research",
  "skill": "deep-research",
  "model": "opus",
  "timeout": 600000,
  "runtime": "claude-cli",
  "trigger": { "type": "dependency" },
  "inputs": {
    "depends": [],
    "files": [],
    "env": ["PPLX_API_KEY"],
    "config": { "expert_name": "{{expert_name}}" }
  },
  "outputs": {
    "artifacts": [
      { "key": "intel-report", "path": "{{workspace}}/sources/intel-report.md", "format": "markdown" },
      { "key": "raw-sources", "path": "{{workspace}}/sources/raw-sources/", "format": "directory" }
    ],
    "metrics": [{ "key": "source_count", "type": "number" }],
    "publish": [{ "domain": "align360.asapai.net", "slug": "{{expert_slug}}-intel" }]
  },
  "execution": {
    "parallel_group": "L0-recon",
    "human_gate": "none",
    "threshold": null,
    "retryable": true,
    "max_retries": 2
  },
  "lifecycle": { "mode": "one-shot" },
  "scope": { "gate": null, "run_params": {} },
  "lens": { "perspective": null, "aggregates": null, "feedback_loop": false },
  "record_state": { "track_per": null, "states": [] }
}

Example 2: expert-framework-creator (L0.25, extract, human gate)

Pattern: Depends on L0 outputs. Runs after recon completes. Has human_gate: "after" so an approver must sign off on the extracted framework before downstream blocks proceed. Uses 3-path convergence (high cost, high quality).
JSON — expert-framework-creator block
{
  "id": "expert-framework-creator",
  "name": "Expert Framework Creator",
  "layer": "L0.25",
  "type": "extract",
  "skill": "expert-framework-creator",
  "model": "opus",
  "timeout": 900000,
  "runtime": "claude-cli",
  "trigger": { "type": "dependency" },
  "inputs": {
    "depends": [
      { "block": "deep-research", "key": "raw-sources" },
      { "block": "expert-recon", "key": "recon-summary" }
    ],
    "files": ["{{workspace}}/sources/**/*"],
    "env": [],
    "config": {}
  },
  "outputs": {
    "artifacts": [{ "key": "expert-framework", "path": "{{workspace}}/expert-framework.json", "format": "json" }],
    "metrics": [
      { "key": "convergence_score", "type": "number" },
      { "key": "evidence_count", "type": "number" }
    ],
    "publish": null
  },
  "execution": {
    "parallel_group": null,
    "human_gate": "after",
    "threshold": null,
    "retryable": true,
    "max_retries": 1
  },
  "lifecycle": { "mode": "one-shot" },
  "scope": { "gate": null, "run_params": {} },
  "lens": { "perspective": null, "aggregates": null, "feedback_loop": false },
  "record_state": { "track_per": null, "states": [] }
}

Example 3: soul-extractor (L2, extract, parallel group)

Pattern: Runs in the L2-extractors parallel group with 4 other extractors. Model is null (inherits from factory config). Depends on L0.25 framework output and L0 raw sources.
JSON — soul-extractor block
{
  "id": "soul-extractor",
  "name": "Soul Extractor",
  "layer": "L2",
  "type": "extract",
  "skill": "soul-extractor",
  "model": null,
  "timeout": 600000,
  "runtime": "claude-cli",
  "trigger": { "type": "dependency" },
  "inputs": {
    "depends": [
      { "block": "expert-framework-creator", "key": "expert-framework" },
      { "block": "deep-research", "key": "raw-sources" }
    ],
    "files": ["{{workspace}}/sources/**/*"],
    "env": [],
    "config": {}
  },
  "outputs": {
    "artifacts": [{ "key": "soul", "path": "{{workspace}}/soul.json", "format": "json" }],
    "metrics": [{ "key": "extraction_completeness", "type": "percentage" }],
    "publish": null
  },
  "execution": {
    "parallel_group": "L2-extractors",
    "human_gate": "none",
    "threshold": null,
    "retryable": true,
    "max_retries": 2
  },
  "lifecycle": { "mode": "one-shot" },
  "scope": { "gate": null, "run_params": {} },
  "lens": { "perspective": null, "aggregates": null, "feedback_loop": false },
  "record_state": { "track_per": null, "states": [] }
}

Example 4: clone-tester (L3.5, validate, threshold + human gate)

Pattern: Validation block with both a score threshold (overall_score >= 85) and a human gate after. If the score is below 85, it auto-retries up to 2 times. After passing threshold, it still requires human approval before the pipeline can finalize. This is the quality checkpoint that gates deployment.
JSON — clone-tester block
{
  "id": "clone-tester",
  "name": "Clone Tester",
  "layer": "L3.5",
  "type": "validate",
  "skill": "clone-tester",
  "model": "opus",
  "timeout": 1200000,
  "runtime": "claude-cli",
  "trigger": { "type": "dependency" },
  "inputs": {
    "depends": [
      { "block": "clone-compiler", "key": "system-prompt" },
      { "block": "clone-compiler", "key": "knowledge-files" },
      { "block": "clone-compiler", "key": "tool-configs" },
      { "block": "expert-framework-creator", "key": "expert-framework" }
    ],
    "files": ["{{workspace}}/artifacts/**/*"],
    "env": [],
    "config": {}
  },
  "outputs": {
    "artifacts": [
      { "key": "test-results", "path": "{{workspace}}/test-results/test-results.json", "format": "json" },
      { "key": "audit-sheet", "path": "{{workspace}}/test-results/audit-sheet.md", "format": "markdown" },
      { "key": "simulation-log", "path": "{{workspace}}/test-results/simulation-log.json", "format": "json" }
    ],
    "metrics": [
      { "key": "overall_score", "type": "percentage" },
      { "key": "governance_violations", "type": "number" }
    ],
    "publish": [{ "domain": "align360.asapai.net", "slug": "{{expert_slug}}-test-results" }]
  },
  "execution": {
    "parallel_group": null,
    "human_gate": "after",
    "threshold": { "metric": "overall_score", "min": 85 },
    "retryable": true,
    "max_retries": 2
  },
  "lifecycle": { "mode": "one-shot" },
  "scope": { "gate": null, "run_params": {} },
  "lens": { "perspective": null, "aggregates": null, "feedback_loop": false },
  "record_state": { "track_per": null, "states": [] }
}

3. Factory Template JSON Structure

A factory template wraps the 18 blocks with shared configuration, parallel group definitions, human gate assignments, threshold rules, and a module mapping that connects extraction outputs to the 9-module knowledge taxonomy.

JSON — Factory template wrapper
{
  "factory": {
    "id": "clone-factory",
    "name": "Clone Factory",
    "version": "1.0.0",
    "pattern": "dag-batch",
    "description": "18-skill recursive expert clone pipeline"
  },
  "config": {
    "expert_name": "{{expert_name}}",
    "expert_slug": "{{expert_slug}}",
    "workspace": "{{workspace_path}}",
    "publish_domain": "{{publish_domain}}",
    "model_default": "opus"
  },
  "blocks": [ // ...18 block definitions (see Section 2 for examples) ],
  "parallel_groups": {
    "L0-recon": ["deep-research", "expert-recon", "masterybook-sync"],
    "L2-extractors": ["soul-extractor", "voice-extractor", "framework-extractor", "resource-extractor", "offer-extractor"],
    "L3-builders": ["clone-compiler", "lead-magnet-builder", "onboarding-builder"]
  },
  "human_gates": [
    { "after_block": "expert-framework-creator", "approvers": ["expert", "product_lead"] },
    { "after_block": "gap-analyzer", "approvers": ["product_lead"] },
    { "after_block": "clone-tester", "approvers": ["expert", "product_lead", "tech_lead"] }
  ],
  "thresholds": [
    { "block": "clone-tester", "metric": "overall_score", "min": 85, "action": "fail" }
  ],
  "module_mapping": {
    "M1_thinking_structures": ["expert-framework-creator", "soul-extractor"],
    "M2_voice_style": ["voice-extractor"],
    "M3_cta_psychology": ["offer-extractor"],
    "M4_embedded_ip": ["framework-extractor"],
    "M5_modularization": ["framework-extractor"],
    "M6_meta_structures": ["framework-extractor"],
    "M7_pattern_recognition": ["soul-extractor"],
    "M8_prompt_templates": ["clone-compiler"],
    "M9_retrieval_patterns": ["clone-compiler"]
  }
}
Template Variables

All {{double_brace}} values are resolved at run-time by the orchestrator. The factory template is static; the orchestrator instantiates it with concrete values for each expert run.

4. Readiness Signal Algorithm

The DAG scheduler continuously evaluates block readiness. A block transitions from pending to ready only when all preconditions are met: dependencies complete, outputs available, human gates cleared, and parallel group capacity allows.

evaluateReadiness(block, run_state)

Pseudocode
function evaluateReadiness(block, run_state):
  // 1. Check if block is already done or running
  if block.state.status in ['done', 'running', 'failed']:
    return block.state.status

  // 2. Check all dependencies
  for dep in block.inputs.depends:
    dep_block = run_state.blocks[dep.block]
    if dep_block.state.status != 'done':
      return 'blocked'
    if dep_block.outputs[dep.key] is missing:
      return 'blocked'

  // 3. Check human gate (before type)
  if block.execution.human_gate == 'before':
    if not run_state.gates[block.id].approved:
      return 'waiting'

  // 4. Check parallel group capacity
  if block.execution.parallel_group:
    running_in_group = count(b for b in run_state.blocks
      if b.execution.parallel_group == block.execution.parallel_group
      and b.state.status == 'running')
    if running_in_group >= MAX_PARALLEL:
      return 'pending'

  // 5. All checks pass
  return 'ready'

handleBlockCompletion(block_id, result, run_state)

Pseudocode
function handleBlockCompletion(block_id, result, run_state):
  block = run_state.blocks[block_id]

  // 1. Update block state
  block.state.status = result.success ? 'done' : 'failed'
  block.state.ended_at = now()
  block.state.score = result.score

  // 2. Check threshold
  if block.execution.threshold:
    if result.score < block.execution.threshold.min:
      if block.state.attempts < block.execution.max_retries:
        block.state.status = 'pending'
        block.state.attempts += 1
        return { action: 'retry' }
      else:
        block.state.status = 'failed'
        return { action: 'failed', reason: 'threshold_not_met' }

  // 3. Check human gate (after type)
  if block.execution.human_gate == 'after':
    block.state.status = 'waiting'
    return { action: 'await_approval', gate: block.id }

  // 4. Evaluate downstream blocks
  for downstream in findDependents(block_id, run_state):
    downstream.state.status = evaluateReadiness(downstream, run_state)

  return { action: 'continue' }
Evaluation Order

The scheduler runs evaluateReadiness on all pending/blocked blocks after every state change. This ensures cascading readiness propagation: when an L0 block completes, L0.25 immediately re-evaluates, and so on down the DAG.

5. State Machine Diagram

Every block has a state.status field managed by the engine. The following diagram shows all valid states and transitions.

pending
blocked
ready
running
done
failed
waiting
FromToCondition
pendingreadyAll dependencies met, no blocking gate
pendingblockedOne or more dependencies not done
blockedreadyAll dependencies resolved
blockedpendingPartial dependencies resolved (re-queue)
readyrunningScheduler picks up block for execution
runningdoneExecution succeeds, threshold met (or no threshold)
runningfailedExecution error or timeout
donewaitingBlock has human_gate: "after"
waitingdoneHuman gate approved
waitingpendingHuman gate rejected (retry)
failedpendingRetryable and attempts < max_retries
pending blocked ready running done failed waiting deps met success error gate retry

6. Parallel Group Semantics

Parallel groups allow multiple blocks to execute concurrently when their individual dependencies are satisfied. This is the primary mechanism for reducing wall-clock time in the pipeline.

How It Works

  • Simultaneous readiness: All blocks in a parallel group become ready at the same time once their respective dependencies are met. The group name is a coordination label, not a dependency.
  • Concurrent launch: The scheduler launches all ready blocks in the group simultaneously. Each block executes independently.
  • Group completion: The group is considered "complete" when ALL blocks in the group reach done status. Partial completion is tracked for progress display.
  • Independent failure: If one block in the group fails, the other blocks continue executing. A failed block in a group does not halt sibling blocks, only downstream blocks that depend on the failed block's output.
  • Progress tracking: The parallel group name is used for progress display: "L2-extractors: 3/5 done"
  • Concurrency limits: Maximum concurrent blocks per group can be configured (default: unlimited). Useful for resource-constrained environments.

Defined Parallel Groups

L0-recon (3 blocks)

deep-research + expert-recon + masterybook-sync — All root nodes with zero dependencies. Fire simultaneously at run start.

L2-extractors (5 blocks)

soul-extractor + voice-extractor + framework-extractor + resource-extractor + offer-extractor — All depend on L0.25 framework. Fire simultaneously after framework is approved. Saves ~60% wall-clock time vs sequential.

L3-builders (3 blocks)

clone-compiler + lead-magnet-builder + onboarding-builder — All depend on L2 extraction outputs. Fire simultaneously after gap analysis is approved.

Concurrency Configuration

JSON — Optional concurrency override
{
  "parallel_groups": {
    "L0-recon": {
      "blocks": ["deep-research", "expert-recon", "masterybook-sync"],
      "max_concurrent": 3   // default: unlimited
    },
    "L2-extractors": {
      "blocks": ["soul-extractor", "voice-extractor", "framework-extractor", "resource-extractor", "offer-extractor"],
      "max_concurrent": 3   // limit to 3 to reduce API pressure
    }
  }
}

7. Human Gate Protocol

Human gates are synchronization points where the pipeline pauses for human review and approval. They ensure that critical outputs are validated before downstream blocks consume them.

Gate Flow

  1. Block completes execution (status transitions to done)
  2. If human_gate == "after": status transitions to waiting
  3. Dashboard surfaces the approval UI with the block's output artifacts
  4. Designated approver reviews outputs
  5. Approve: Block status transitions to done; downstream blocks are re-evaluated for readiness
  6. Reject: Block status transitions to pending (auto-retry) or failed (abort), depending on retry budget
  7. Reject with feedback: Feedback is stored in run_state.gates[block_id].feedback and passed to the skill on retry
  8. Approver roles are configurable per gate: expert, product_lead, tech_lead

Gate Configuration in Factory Template

JSON — Human gate definitions
"human_gates": [
  {
    "after_block": "expert-framework-creator",
    "approvers": ["expert", "product_lead"],
    "timeout_hours": 48,
    "auto_approve_on_timeout": false
  },
  {
    "after_block": "gap-analyzer",
    "approvers": ["product_lead"],
    "timeout_hours": 24,
    "auto_approve_on_timeout": false
  },
  {
    "after_block": "clone-tester",
    "approvers": ["expert", "product_lead", "tech_lead"],
    "timeout_hours": 72,
    "auto_approve_on_timeout": false
  }
]

API Endpoints

POST /api/a360/factory-run/{run_id}/gate/{block_id}/approve
JSON — Approve request body
{
  "approver": "will@align360.io",
  "role": "product_lead",
  "notes": "Framework looks solid. FORGE dimensions validated against source material."
}
POST /api/a360/factory-run/{run_id}/gate/{block_id}/reject
JSON — Reject request body
{
  "approver": "samuel@flc.com",
  "role": "expert",
  "action": "retry",
  "feedback": "Missing the 'Hat Debate' pattern. Re-run with emphasis on Phase 3 deliberation structures."
}
Gate Timeout

If no approver acts within the configured timeout_hours, the gate does NOT auto-approve (by default). The pipeline stays paused. Set auto_approve_on_timeout: true only for non-critical gates in automated environments.

8. Threshold / Retry Logic

Thresholds enforce minimum quality standards. When a block reports a score metric, the engine compares it against the configured minimum. Below-threshold results trigger automatic retries up to the configured limit.

Threshold Evaluation Flow

  1. Block completes with a score metric (e.g., overall_score: 82)
  2. Engine checks: score >= threshold.min?
  3. Yes: Proceed to human gate (if configured) or mark done
  4. No, attempts < max_retries: Status transitions to pending (auto-retry). Attempt counter increments.
  5. No, attempts >= max_retries: Status transitions to failed
  6. A failed threshold block prevents all downstream blocks from becoming ready
  7. Human override: A human gate approver can override a below-threshold failure with justification

Example: clone-tester Threshold Scenario

Threshold Config

metric: overall_score | min: 85 | max_retries: 2

AttemptScoreResultNext Status
182%Below thresholdpending (auto-retry)
284%Below thresholdpending (auto-retry)
383%Below threshold, max retries exhaustedfailed

At this point, a human approver can still override:

JSON — Human override of failed threshold
// POST /api/a360/factory-run/{run_id}/gate/clone-tester/approve
{
  "approver": "jason@athio.ai",
  "role": "tech_lead",
  "override": true,
  "justification": "Alpha quality acceptable at 83%. Known gap is CTA psychology (Module 3). Ship and fix in next iteration."
}

Threshold Configuration in Factory Template

JSON — Threshold definitions
"thresholds": [
  {
    "block": "clone-tester",
    "metric": "overall_score",
    "min": 85,
    "action": "fail",          // "fail" = block downstream, "warn" = log only
    "override_allowed": true  // can a human override?
  }
]
Retry Intelligence

On retry, the engine passes the previous attempt's score and any human feedback to the skill. This allows the skill to adjust its approach. For example, the clone-tester can focus on the weakest dimensions from the prior attempt.

Block Schema Reference v1.0 — Process Factory Engine — March 2026