injectctl is a local, offline-friendly command-line tool that turns security evidence into draft reports or exercise injects.
In plain terms, you give it things like:
- screenshots
- copied notes
nmapoutput- Nessus exports
- simple instructions
It gives you:
- a human-readable Markdown report
- a machine-readable JSON file
- a PDF
- a separate evidence index in Markdown and JSON
It is designed for blue teams, assessment teams, and exercise planners who want a fast first draft without sending data to a cloud service.
This project is currently a v1 release candidate.
That means:
- the core workflow works
- local builds and tests are passing
- the tool is usable today
- the interface should now be mostly stable
- you should treat outputs as analyst-reviewed drafts, not final truth
injectctl supports two main workflows:
-
assessmentTurn evidence into a draft assessment report with findings, impact, remediation, and evidence links. -
injectTurn evidence into a draft inject pack for exercises such as tabletop or blue-team scenarios.
To use the application, you need:
- the
injectctlbinary for your platform Ollamarunning locally- at least one local Gemma 4 model profile
gemma4:26bfor the defaultbalancedprofilegemma4:e4bas the normal fallback- optionally
gemma4:31bfor thequalityprofile - optionally
tesseractif you want OCR from screenshots
You do not need Go installed on the target machine if you are running a released binary.
This project depends on two external local tools:
Ollamafor local AI inferenceTesseractfor OCR from screenshots and images
If Ollama is missing, the run will fail.
If Tesseract is missing, image OCR will be reduced or unavailable depending on the artifact and model path.
Official download:
- Open the Ollama download page.
- Download the Windows installer.
- Run the installer.
- After install, start Ollama from the Start menu or let the installer start it automatically.
- Open a new PowerShell window and verify the CLI is available:
ollama --version- Verify the local service responds:
ollama listIf Ollama is running correctly, ollama list should return a model table or an empty list instead of a connection failure.
- Download the macOS installer from the Ollama download page.
- Install and launch Ollama.
- Verify:
ollama --version
ollama listUse the install instructions from the Ollama download page, then verify:
ollama --version
ollama listAfter Ollama is installed and running, pull the models used by injectctl:
ollama pull gemma4:26b
ollama pull gemma4:e4b
ollama pull gemma4:31bVerify they are present:
ollama listYou should see:
gemma4:26bgemma4:e4bgemma4:31b
Official installation reference:
For Windows, the Tesseract project documentation currently points users to the UB Mannheim Windows installers:
- Open the UB Mannheim Tesseract page.
- Download the current Windows installer.
- Run the installer.
- Install to the default path unless you have a reason to change it:
C:\Program Files\Tesseract-OCR
- Make sure that folder is in your
PATH.
To check from PowerShell:
tesseract --versionIf PowerShell says tesseract is not recognized, add this directory to your user or system PATH and open a new shell:
C:\Program Files\Tesseract-OCR
The Tesseract installation guide documents Homebrew and MacPorts. Homebrew is usually simplest:
brew install tesseract
tesseract --versionThe Tesseract installation guide documents package-manager installation by distribution. On Ubuntu:
sudo apt install tesseract-ocr
tesseract --versionOnce Ollama and Tesseract are installed, verify the full local environment:
injectctl doctorFor a stronger validation, run a live smoke test against your configured model:
injectctl doctor --profile balanced --smokeYou want to see:
- Ollama reachable
- expected model profile resolved
- installed models listed
- smoke test passed
- OCR available
Make sure Ollama is installed and running.
Then pull the default model:
ollama pull gemma4:26b
ollama pull gemma4:e4bOptional quality profile:
ollama pull gemma4:31bRun:
injectctl doctorYou want to see:
- Ollama reachable
- the selected profile resolved to installed models
- OCR available if you plan to use screenshots
Example:
my-run/
artifacts/
screenshot.png
scan.nmap
notes.txt
job.yaml
Put your evidence into artifacts/.
Assessment example:
injectctl init manifest --mode assess --out job.yamlInject example:
injectctl init manifest --mode inject --out job.yamlThen edit job.yaml to describe your case.
If you want a complete working example bundle instead of starting from scratch:
injectctl init demo --mode assess --out .\demoThat creates:
- a ready-to-run
job.yaml - sample
notes.txt - sample
scan.nmap - a sample screenshot
terminal.png
Assessment:
injectctl assess run --manifest .\job.yaml --input .\artifacts --out .\outInject:
injectctl inject run --manifest .\job.yaml --input .\artifacts --out .\outAfter a successful run, injectctl now prints a short completion summary with the status, output directory, project snapshot directory, AI model usage, and generated file names.
You will usually get:
assessment-report-draft.mdorinject-pack-draft.mdassessment-report-data.jsonorinject-pack-data.jsonassessment-report-review.pdforinject-pack-review.pdfassessment-evidence-index.mdorinject-evidence-index.mdassessment-evidence-index.jsonorinject-evidence-index.json
The default Markdown and JSON outputs now also record the AI models actually used during the run, plus batch counts when oversized evidence had to be split across multiple synthesis passes.
If generation fails, the tool now produces an evidence-only result with an explicit error report instead of pretending a polished draft was created.
Assessment example:
mode: assess
title: Example Assessment
client: Example Corp
environment: Production
classification: TLP:AMBER
instructions: >
Turn the supplied screenshots, scan outputs, and notes into a draft corporate assessment report.
# template: ./templates/default/assessment.md.j2
# template_dir: ./templates/library
artifacts:
- ./artifacts
ai:
provider: ollama
endpoint: http://127.0.0.1:11434
profile: balanced
# model: gemma4:26b
# fallback_model: gemma4:e4b
temperature: 0.2
max_tokens: 2048
timeout_seconds: 90
max_prompt_artifacts: 12
max_prompt_observations: 40
# prompt_dir: ./prompts
output:
formats:
- markdown
- json
- pdf
project_dir: ./project
redaction_rules:
- '(?m)\b\d{1,3}(?:\.\d{1,3}){3}\b'More examples:
-
modeChooseassessorinject. -
titleThe name shown in the final output. -
clientThe organization or customer name. -
environmentThe environment being assessed or exercised, such asProduction. -
classificationYour handling label, such asTLP:AMBER. -
instructionsTell the model what you want. Keep this simple and direct. -
templateOptional Markdown template file for the final Markdown output. -
template_dirOptional folder containing a collection of templates. Iftemplateis not set,injectctlwill score the available templates and auto-select the best match for the current mode and instructions. -
artifactsOne or more files or folders containing the evidence. -
ai.endpointUsuallyhttp://127.0.0.1:11434for local Ollama. -
ai.profileSimple model preset. Usefast,balanced, orquality. -
ai.modelOptional explicit primary model override. If omitted, the selected profile sets it. -
ai.fallback_modelOptional explicit fallback override. If omitted, the selected profile sets it. -
ai.timeout_secondsHow long the tool waits for Ollama before timing out a request. -
ai.max_prompt_artifactsLimits how many artifacts are sent into the AI prompt context. -
ai.max_prompt_observationsLimits how many normalized observations are sent into the AI prompt context. -
ai.prompt_dirOptional folder containing custom AI prompt files such asassessment_system.txtandinject_system.txt. -
output.formatsWhich outputs to create:markdown,json,pdf. -
output.project_dirOptional folder where the tool stores a local project copy of the run. -
output.redaction_rulesOptional regex or literal strings to redact from outputs.
Current built-in parsing supports:
- screenshots and images
- plain text notes
nmaptext outputnmapXML- Nessus CSV
- Nessus
.nessusXML
Images are handled like this:
- OCR is attempted first if
tesseractis installed. - Images are also passed to Ollama for multimodal understanding when possible.
The AI layer now works like this:
injectctlchecks Ollama availability.- It resolves an AI profile such as
balancedorqualityinto primary and fallback models. - It checks whether the primary model is installed.
- If the primary model is missing and the fallback model exists, it switches to the fallback automatically.
- Prompt input is still bounded by configurable artifact and observation limits, but oversized evidence sets are now split into multiple AI batches and consolidated into one final draft.
- Prompt system instructions come from embedded defaults unless you provide a custom
prompt_dir. - The model must return structured JSON.
- If the JSON is malformed, the tool retries once with a repair prompt.
- If synthesis still fails, the tool emits an
evidence_onlyresult with an error report.
Checks whether your local environment is ready.
Example:
injectctl doctorOptional flags:
injectctl doctor --endpoint http://127.0.0.1:11434 --model gemma4:26b --fallback-model gemma4:e4bProfile-based example:
injectctl doctor --profile quality --smokeCreates a starter manifest.
Example:
injectctl init manifest --mode assess --out job.yamlCreates a full demo folder with sample artifacts and a starter manifest.
Example:
injectctl init demo --mode assess --out .\demoBuilds a draft assessment report.
Example:
injectctl assess run --manifest .\job.yaml --input .\artifacts --out .\outBuilds a draft inject pack.
Example:
injectctl inject run --manifest .\job.yaml --input .\artifacts --out .\outChecks that a custom Markdown template can be parsed.
Example:
injectctl template validate --template .\templates\custom-report.md.j2Lists candidate templates from a directory in the order they would be considered.
Example:
injectctl template list --dir .\templates\library --mode assessTemplates support Jinja-style Markdown templates.
Legacy Go text/template files with extensions like .tmpl are still accepted for backward compatibility, but .j2 or .jinja is the recommended v1 format.
That means placeholders look like:
{{ config.title }}
{{ draft.executive_summary }}
{% if draft.findings %}
{{ draft.findings|length }} findings
{% endif %}The built-in templates are here:
The shipped template library is here:
- templates/library/assessment-ir-report.md.j2
- templates/library/inject-business-brief.md.j2
- templates/library/inject-legal-memo.md.j2
- templates/library/inject-technical-worksheet.md.j2
Selection rules:
- if
templateis set, that file is used - if
templateis not set andtemplate_diris set,injectctlscores the directory contents and auto-selects the best match - if nothing in
template_diris compatible, the built-in default template is used
You can keep converted or source material in the same broader templates/ tree, but only text-based template files are selectable:
.j2.jinja.jinja2.tmpl.tpl.md
Direct .docx rendering is not supported. If you want to reuse Word templates, convert them first:
python .\scripts\docx_to_markdown.py .\templates --out-dir .\templates\converted-docxThose converted Markdown files are source material for building live templates. The ready-to-use shipped live templates are in templates/library/.
Important:
- custom templates affect Markdown output
- PDF output uses the built-in PDF layout
Custom AI system prompts are separate from report templates.
If you set ai.prompt_dir, the tool will look for:
assessment_system.txtinject_system.txt
Best for:
- human review
- editing
- turning into internal reports
Best for:
- automation
- pipelines
- storing normalized findings or injects
- reviewing detailed AI/error state
Best for:
- sharing with non-technical stakeholders
- executive review
- preserving layout
Best for:
- auditing exactly which artifacts were processed
- checking which observations were linked to each artifact
- reviewing snippets without reading the full report
If output.project_dir is set, the project folder now also keeps:
- the manifest snapshot
- the full run JSON
evidence-index.jsonevidence-index.mdrun-summary.jsonoutput-inventory.jsonrun-log.jsonloutputs/with copied Markdown, JSON, and PDF artifacts for that run
run-summary.json includes the configured model, the actual models used, stage-level AI execution details, and the batch count for chunked synthesis runs.
output-inventory.json records the generated output files, their paths, sizes, and timestamps.
run-log.jsonl records structured lifecycle events for the run so you can audit what happened without reading console output.
This tool is meant to help analysts, not replace them.
You should always:
- review findings before distribution
- verify remediation text
- confirm evidence links
- check severity and impact wording
Check that Ollama is running and listening on http://127.0.0.1:11434.
Start by verifying the local CLI and service:
ollama --version
ollama listIf ollama list fails, launch Ollama first and then rerun injectctl doctor.
Pull the model:
ollama pull gemma4:26bInstall tesseract so OCR can run locally.
Verify it is available:
tesseract --versionIf the command is not found on Windows, add this to your PATH and open a new shell:
C:\Program Files\Tesseract-OCR
This means the tool collected and normalized the evidence, but model generation failed. Review the JSON output and the error report, fix the local model/runtime issue, and run again.
Check your redaction_rules. They can be regex patterns or literal strings. Invalid regex patterns are treated as literal text and added to warnings.
If you want to build the binary yourself, you need Go installed.
Test the project:
go test ./...Build the local binary:
go build ./cmd/injectctlUse the release script to build all supported targets:
.\scripts\release.ps1 -Version v0.1.0Artifacts are written under dist/<version>/.
Current release targets:
windows-amd64windows-arm64linux-amd64linux-arm64darwin-amd64darwin-arm64
The release script also creates:
- zipped binaries
sha256sums.txt
GitHub Actions also builds and uploads per-platform artifacts for each run.
- still analyst-review-first, not autopublish
- no live multi-user server mode
- no embedded local model runtime
- OCR depends on an external local install of
tesseract - PDF templates are not user-customizable yet
- outputs should still be reviewed by a human analyst