15 Actions & 12 Primitives: Two-Tier Action Pipeline
To eliminate LLM guesswork over code metrics, dependency versions, runtime test pass rates, CVE counts, and refactoring blast radius, pni501 decouples declarative workflow authoring from execution mechanics. For each of the 6 supported languages (Python, Java, PHP, Go, TypeScript, and JavaScript), workflows compose 15 core composite YAML actions (12 universal common/ actions + 3 language-specific <lang>/ actions) that flatten into 12 canonical PrimitiveType steps—pairing 6 auto-executed Python analyzers with 6 schema-enforced, repository-grounded AI and gate primitives.
Source Code
from drawlib.canvas import save, setup
from drawlib.diagrams.architecture import ArchitectureDiagram, Node, NodeGroup, PhosphorIcon
from drawlib.styles import Styles
setup(width=164, height=96, dpi=150)
diag = ArchitectureDiagram(
node_style=Styles.PrimaryBold,
node_text_style=Styles.DarkBold.patch(text_size=10.0),
edge_style=Styles.DarkBold,
edge_text_style=Styles.DarkBold.patch(text_size=10.0),
node_card_style=Styles.WhiteBordered.patch(shape_r=1.6),
)
wf_node = diag.add(
Node(
"Workflow YAML\n15 Composite Actions\n(12 common + 3 <lang>)",
width=35.0,
height=20.0,
icon=PhosphorIcon.FILE_CODE,
icon_size=6.0,
),
xy=(20.0, 69.0),
)
mgr_node = diag.add(
Node(
"Action Manager\n(Cascade & Flatten)",
width=35.0,
height=19.0,
icon=PhosphorIcon.STACK,
icon_size=6.0,
style=Styles.WhiteBold,
text_style=Styles.WhiteBold.patch(text_size=10.2),
card_style=Styles.PrimaryFlat.patch(shape_r=1.6),
),
xy=(20.0, 27.0),
)
det_group = diag.add(
NodeGroup(
title="6 Deterministic Auto-Executed Python Primitives",
width=114.0,
height=43.0,
style=Styles.Neutral.patch(shape_r=2.0),
text_style=Styles.PrimaryBold.patch(text_size=10.5, halign="left", valign="top"),
),
xy=(46.0, 50.0),
)
d1 = det_group.add(
Node("project_inspect", width=24.5, height=13.5, icon=PhosphorIcon.FILE_MAGNIFYING_GLASS, icon_size=5.2),
xy=(15.0, 26.5),
)
d2 = det_group.add(
Node("ast_analyze", width=24.5, height=13.5, icon=PhosphorIcon.TREE_STRUCTURE, icon_size=5.2),
xy=(43.5, 26.5),
)
d3 = det_group.add(
Node("run_check", width=24.5, height=13.5, icon=PhosphorIcon.TERMINAL_WINDOW, icon_size=5.2),
xy=(72.0, 26.5),
)
d4 = det_group.add(
Node("security_scan", width=24.5, height=13.5, icon=PhosphorIcon.SHIELD_WARNING, icon_size=5.2),
xy=(15.0, 10.0),
)
d5 = det_group.add(
Node("web_pentest", width=24.5, height=13.5, icon=PhosphorIcon.BUG, icon_size=5.2),
xy=(43.5, 10.0),
)
d6 = det_group.add(
Node("migration_analyze", width=24.5, height=13.5, icon=PhosphorIcon.GIT_DIFF, icon_size=5.2),
xy=(72.0, 10.0),
)
facts_node = det_group.add(
Node(
".pni/cache/<wf>/\nfacts.json",
width=22.5,
height=29.0,
icon=PhosphorIcon.DATABASE,
icon_size=5.8,
style=Styles.SecondaryBold,
card_style=Styles.SecondaryNeutral.patch(shape_r=1.6),
),
xy=(100.0, 18.2),
)
ai_group = diag.add(
NodeGroup(
title="6 Schema-Guided & Grounded AI / Gate Primitives",
width=114.0,
height=43.0,
style=Styles.Neutral.patch(shape_r=2.0),
text_style=Styles.SecondaryBold.patch(text_size=10.5, halign="left", valign="top"),
),
xy=(46.0, 3.0),
)
a1 = ai_group.add(
Node("load_rules", width=33.0, height=13.5, icon=PhosphorIcon.BOOK_OPEN_TEXT, icon_size=5.2),
xy=(20.0, 26.5),
)
a2 = ai_group.add(
Node("record_architecture", width=33.0, height=13.5, icon=PhosphorIcon.BLUEPRINT, icon_size=5.2),
xy=(57.0, 26.5),
)
a3 = ai_group.add(
Node("ai_interpret", width=33.0, height=13.5, icon=PhosphorIcon.BRAIN, icon_size=5.2),
xy=(94.0, 26.5),
)
a4 = ai_group.add(
Node(
"emit_score",
width=33.0,
height=13.5,
icon=PhosphorIcon.MEDAL,
icon_size=5.2,
style=Styles.PrimaryBold,
card_style=Styles.PrimaryNeutral.patch(shape_r=1.6),
),
xy=(20.0, 10.0),
)
a5 = ai_group.add(
Node(
"emit_migration_plan",
width=33.0,
height=13.5,
icon=PhosphorIcon.PATH,
icon_size=5.2,
style=Styles.PrimaryBold,
card_style=Styles.PrimaryNeutral.patch(shape_r=1.6),
),
xy=(57.0, 10.0),
)
a6 = ai_group.add(
Node(
"write_drawlib_report",
width=33.0,
height=13.5,
icon=PhosphorIcon.CHART_POLAR,
icon_size=5.2,
style=Styles.SuccessBold,
card_style=Styles.SuccessNeutral.patch(shape_r=1.6),
),
xy=(94.0, 10.0),
)
diag.connect(wf_node, mgr_node, label="normalize", routing="orthogonal")
mgr_node.fork([det_group, ai_group], at_x=41.5, style=Styles.PrimaryBold)
diag.connect(d3, facts_node, routing="orthogonal", style=Styles.SecondaryBold)
diag.connect(d6, facts_node, routing="orthogonal", style=Styles.SecondaryBold)
diag.draw(xy=(0.0, 0.0))
save()
1. Two-Tier Action Expansion (15 Composite Actions -> 12 Primitives)
Workflow definitions in .pni/workflows/*.yaml (WorkflowDefinition) stay concise because src/pni/_actions/base_model.py separates reusable domain audit bundles from low-level execution steps:
- Tier 1 — Composite Actions (
CompositeActionDefinition): Domain-focused YAML specifications invoked viauses: <action_id>. Each composite action bundles default engineeringrules, orderedCompositePrimitiveSpecentries, defaultwithparameters, and domain-specific prompt instructions. - Tier 2 — Canonical Primitives (
PrimitiveStep&PrimitiveType): The12core execution primitives referenced inside composite YAMLs or directly in a workflow step viaaction: <primitive_type>. Every stateful workflow run and ad-hocrun-actioncall operates over flattenedPrimitiveStepinstances.
1.1 Catalog of the 15 Per-Language Composite Actions (01 through 15)
For any target language (python, java, php, go, typescript, or javascript), src/pni/_actions/ provides 15 core composite YAML actions (12 universal actions in common/ + 3 language-scoped actions in <lang>/):
| Stage | Composite uses: ID |
Scope | Expanded PrimitiveType Sequence |
Default Attached Rules & Purpose |
|---|---|---|---|---|
01 |
repo_structure_audit(01_project_inspect) |
<lang>/ |
project_inspect -> ai_interpret |
<lang>/dependencies, common/supply_chain, common/documentation, common/git_hygiene, common/security |
02 |
architecture_analysis(02_architecture) |
common/ |
record_architecture (×3: purpose_and_stack, layers_and_modules, flows_and_state) |
common/architecture — Grounded 3-aspect system comprehension saved to architecture.json |
03 |
<lang>_ast_audit(03_ast_quality) |
<lang>/ |
ast_analyze -> ai_interpret |
<lang>/code_quality, <lang>/typing, <lang>/modernization, and detected framework rules |
04 |
<lang>_test_audit(04_test_suite) |
<lang>/ |
ai_interpret (consumes AstFacts) |
<lang>/testing — Evaluates test isolation, mirror layout, and assertion density |
05 |
supply_chain_audit(05_supply_chain) |
common/ |
ai_interpret (consumes ProjectFacts) |
common/supply_chain, common/git_hygiene, common/security — OpenSSF & CI/CD governance |
06 |
library_hygiene_audit(06_library_hygiene) |
common/ |
ai_interpret |
common/library_hygiene, common/documentation — SemVer API surface & minimal dependencies |
07 |
cli_guidelines_audit(07_cli_guidelines) |
common/ |
ai_interpret |
common/cli_guidelines, common/error_handling — Clig.dev ergonomics, --help, exit codes |
08 |
service_readiness_audit(08_service_readiness) |
common/ |
ai_interpret |
common/twelve_factor, common/production_readiness, common/observability, common/resilience |
09 |
container_runtime_audit(09_runtime_check) |
common/ |
run_check -> ai_interpret |
common/container_hygiene, common/production_readiness — Offline --network=none tests & smoke probe |
10 |
security_vulnerability_audit(10_security_scan) |
common/ |
security_scan -> ai_interpret |
common/security, common/supply_chain, common/container_hygiene — Socketless Trivy FS + image tar scan |
11 |
web_penetration_audit(11_web_pentest) |
common/ |
web_pentest -> ai_interpret |
common/security, common/resilience — Loopback container boot + live httpx security probes |
12 |
emit_score(12_emit_score) |
common/ |
emit_score |
Aggregates findings, hotspots, rule compliance & stamps reports/<target>_score.json |
13 |
write_drawlib_report(13_audit_report) |
common/ |
write_drawlib_report (report_kind: audit) |
common/reporting — Emits blueprint.json and verifies 7-chapter A4 PDF audit deliverable |
14 |
migration_proposal(14_migration_plan) |
common/ |
migration_analyze -> ai_interpret -> emit_migration_plan |
common/migration_planning, common/architecture — Waves 1..4, Tarjan SCC cuts & *_migration_plan.json |
15 |
write_migration_report(15_migration_report) |
common/ |
write_drawlib_report (report_kind: migration) |
common/reporting, common/migration_planning — Compiles 7-chapter Migration A4 PDF report |
Progress Tracking Extension (
category: progress): In addition to the 15 core audit and migration actions,common/also includesprogress_assessment(progress_analyze->ai_interpret->emit_progress) andwrite_progress_report(report_kind: progress) to measure multi-sprint remediation delta against a baseline audit and migration plan.
1.2 Three-Layer Cascade & Parameter Merging (_actions/manager.py)
When normalize_workflow_steps() expands a workflow, expand_composite_action() resolves uses: via local (.pni/actions/) > <active_lang>/ > common/ and merges three configuration layers:
- Parameters (
params): Workflow-level target/output paths (workflow_id,target_root,source_targets,test_targets,doc_targets,facts_path,score_path,output_dir) merge with the workflow step'swith:block, overriding primitive-levelwith:defaults ({**prim.with_params, **override_params}). - Rules (
rules): Composite rules, workflow-steprules:additions, and primitive-level rules are concatenated and deduplicated in declaration order (dict.fromkeys). - Provenance IDs: Workflow-step
prompt:overrides append cleanly below base prompts, producing compound step IDs ({step_id}__{idx}_{prim.type.value}) withsource_action=comp.idbefore SQLite assigns sequential action IDs (act-01,act-02, ...).
id: web_penetration_audit
name: Live Web Application Penetration Testing Audit
description: Starts the target web service in an isolated loopback container and executes Python + httpx security probes.
rules:
- common/security
- common/resilience
primitives:
- type: web_pentest
name: Execute Live Web Penetration Test Suite
with:
pentest_timeout_sec: 180
- type: ai_interpret
name: Evaluate Live Penetration Test Findings & Attack Surface
prompt: |
Review PentestFacts (discovered endpoints, failed security probes, CWE tags, and HTTP evidence).
Cross-reference with AST dangerous_sinks and api_endpoints to prioritize P0-P2 remediations.
2. Complete Catalog of the 12 Canonical Primitives
In src/pni/_actions/ai_actions.py and src/pni/_workflows/engine.py, every get-action prompt injects get_expected_input_schema_json(), and every push-action call validates both Pydantic v2 structure and repository path grounding (_verify_grounded_paths() rejects any file or module path absent from disk and AstFacts.module_inventory):
Source Code
from drawlib.canvas import save, setup
from drawlib.smartarts import Table
from drawlib.styles import Styles
setup(width=162, height=118, dpi=150)
headers_and_rows = [
["Primitive", "Mode", "Validated Push Schema", "Grounding & Side Effects"],
[
"project_inspect",
"Deterministic",
"DeterministicAckInput",
"Parses manifests, lockfiles & governance\n-> .pni/cache/<wf>/facts.json",
],
[
"ast_analyze",
"Deterministic",
"DeterministicAckInput",
"Runs 9 Tree-sitter AST checkers (6 langs)\n-> .pni/cache/<wf>/facts.json",
],
[
"run_check",
"Deterministic",
"DeterministicAckInput",
"Materializes .pni/dockerfiles/, runs\n--network=none unit tests & coverage",
],
[
"security_scan",
"Deterministic",
"DeterministicAckInput",
"Runs socketless Trivy FS + image tar scan\n-> security_facts.json & facts.json",
],
[
"web_pentest",
"Deterministic",
"DeterministicAckInput",
"Boots 127.0.0.1 loopback container & runs\n.pni/pentests/<target>/ httpx probes",
],
[
"migration_analyze",
"Deterministic",
"DeterministicAckInput",
"Computes Waves 1..4, Tarjan SCC cuts,\ncontracts & DEC-XX -> migration_facts.json",
],
[
"load_rules",
"AI / Gate",
"DeterministicAckInput",
"Resolves & injects cascaded Markdown\nengineering rules into prompt context",
],
[
"record_architecture",
"AI / Grounded",
"SystemProfile | StructureMap |\nExecutionFlowMap",
"Verifies paths against module_inventory\n-> .pni/cache/<wf>/architecture.json",
],
[
"ai_interpret",
"AI / Grounded",
"InterpretationInput",
"Grounds findings/action_items & runs\nnormalize_step_rule_checks() per rule",
],
[
"emit_score",
"AI + Aggregator",
"ScoreResult",
"Runs aggregator.py digest + metric stamp\n-> reports/<target>_score.json",
],
[
"emit_migration_plan",
"AI + Grounded",
"MigrationPlanResult",
"Grounds As-Is paths + attaches MigrationFacts\n-> reports/<target>_migration_plan.json",
],
[
"write_drawlib_report",
"AI + Compiler",
"ReportCompletionInput",
"Emits blueprint.json & verifies non-empty\ncompiled PDF deliverable on disk",
],
]
tbl = Table(
cell_style=Styles.White,
text_style=Styles.Dark.patch(text_size=10.0),
header_cell_style=Styles.PrimaryFlat,
header_text_style=Styles.WhiteBold.patch(text_size=10.5),
border_style=Styles.MutedThin,
has_header=True,
)
tbl.set_style_cell_evenodd(
even_color=Styles.Neutral.shape_fill_color,
even_text_style=Styles.Dark.patch(text_size=10.0),
odd_color=Styles.White.shape_fill_color,
odd_text_style=Styles.Dark.patch(text_size=10.0),
)
tbl.set_style_cell(
background_color=Styles.PrimaryFlat.shape_fill_color,
text_style=Styles.WhiteBold.patch(text_size=10.5),
rows=[0],
)
tbl.set_style_cell(
background_color=Styles.SecondaryNeutral.shape_fill_color,
text_style=Styles.SecondaryBold.patch(text_size=10.0),
rows=[1, 2, 3, 4, 5, 6],
columns=[0],
)
tbl.set_style_cell(
background_color=Styles.PrimaryNeutral.shape_fill_color,
text_style=Styles.PrimaryBold.patch(text_size=10.0),
rows=[7, 8, 9, 10, 11, 12],
columns=[0],
)
col_widths = [31.0, 23.0, 39.0, 63.0]
row_heights = [8.2] + [8.6] * 12
tbl.draw_flexible(
xy=(3.0, 114.5),
column_widths=col_widths,
row_heights=row_heights,
data=headers_and_rows,
align="top_left",
)
save()
2.1 Deterministic Auto-Execution & WorkflowFactsBundle Persistence
Whenever pni workflows get-action (or push-action) reaches one of the 6 deterministic primitives (project_inspect, ast_analyze, run_check, security_scan, web_pentest, or migration_analyze), _execute_deterministic_step_if_needed() runs the corresponding Python analyzer once:
- SQLite & JSON Dual Persistence: The serialized analyzer output is stored in
action_runs.deterministic_output_jsoninside.pni/cache/workflow_state.dband merged into.pni/cache/<workflow_id>/facts.json(WorkflowFactsBundle). - Zero Re-Execution on Retry: Subsequent
get-actioncalls read the cached JSON directly from SQLite unless the operator explicitly rewinds the workflow back to that step viapni workflows rewind <run_id> <selector>.
2.2 Grounding Gates & Synthesis Across Cognitive Primitives
- Aspect-Separated Architecture Comprehension (
record_architecture->architecture.json): Parameterized viawith: {aspect: purpose_and_stack | layers_and_modules | flows_and_state},record_architecturesplits codebase comprehension into three focused schemas (SystemProfile,StructureMap,ExecutionFlowMap)._validate_and_persist_architecture()checks everylayers[].paths,modules[].path,entry_points, andinvolved_filesentry againstAstFacts.module_inventoryand the workspace before persisting.pni/cache/<workflow_id>/architecture.json. - Per-Rule Compliance & Grounded Reasoning (
ai_interpret->InterpretationInput): Requires a0..100step_score, explicitRuleCheckResultverdicts (pass,warn,fail,not_applicable), groundedfindings, andP0–P2action_items. On push,engine.pyverifies everyfile_pathandtarget_filesentry and invokesnormalize_step_rule_checks()(aggregator.py) so every active rule on the step is guaranteed a stamped compliance verdict. - Deterministic Digest & Score Stamping (
emit_score-><target>_score.json):_enrich_score_result()runscompile_workflow_digest()(src/pni/_workflows/aggregator.py) to deduplicate findings, group co-located violations intoconsolidated_findings, compute per-filemodule_hotspots(0.0..1.0risk density), derive canonicalS–Dgrade, attachRuntimeFacts/SecurityFacts/PentestFacts, and overwritemetrics_snapshotdirectly from programmatic facts before writingreports/<target>_score.json. - Grounded Migration Plan Synthesis (
emit_migration_plan-><target>_migration_plan.json):validate_and_persist_migration_plan()(_migration_engine.py) validatesMigrationPlanResult(transformation_axes,target_architecture,component_mappings,phases,pr_backlog,decision_log), verifies all referenced As-Is source paths exist in the repository, attaches deterministicMigrationFacts, and writesreports/<target>_migration_plan.json. - Blueprint-Guided Visual Report Gate (
write_drawlib_report->ReportCompletionInput):render_drawlib_report_guide()pre-computes.pni/cache/<workflow_id>/blueprint.json(ormigration_blueprint.json) for the 7-chapter Drawlibdocreport (00_cover.md..06_*.md), and_validate_report_completion()verifies on disk that every file listed inReportCompletionInput.generated_filesexists inside the workspace withst_size > 0.
Continue to Analyzers & Live Pentest for a deep dive into the 9 Tree-sitter AST checkers and the isolated Docker/Podman runtime, Trivy, and penetration testing engines, or see 7-Axis Scoring Model for how emit_score computes final grades.