1. Installation
Requirements: Java 17 or later. An Anthropic or OpenAI API key.
Linux / macOS
curl -fsSL https://bakalarsoftware.com/dl/install.sh | bash
Downloads the latest fat JAR to ~/.sdlc/bin/, writes an sdlc wrapper script, and adds ~/.sdlc/bin to your PATH.
Windows (PowerShell)
irm https://bakalarsoftware.com/dl/install.ps1 | iex
Downloads the JAR to %USERPROFILE%\.sdlc\bin\, writes an sdlc.bat wrapper, and adds %USERPROFILE%\.sdlc\bin to your user PATH. Restart your terminal after install, or load the new PATH immediately:
$env:PATH = "$env:USERPROFILE\.sdlc\bin;$env:PATH"
Manual install (all platforms)
Download sdlc-orchestrator.jar from bakalarsoftware.com/dl/sdlc-orchestrator.jar and run it directly. No installer needed — it is a self-contained JAR.
java -jar sdlc-orchestrator.jar --help
Verify the install
sdlc --version
2. Configuration
All configuration lives in ~/.sdlc/sdlc-local.properties. Create this file before your first run.
Minimal configuration (no Jira)
llm.anthropicApiKey=sk-ant-...
This is enough to run the pipeline using --title to provide the ticket inline.
Full configuration example
# ── LLM provider (pick one) ──────────────────────────────────────────────────
llm.anthropicApiKey=sk-ant-...
# llm.openAiApiKey=sk-...
# llm.ollamaBaseUrl=http://localhost:11434 # local embeddings via Ollama
# ── Jira (optional) ──────────────────────────────────────────────────────────
jira.baseUrl=https://yourco.atlassian.net
jira.email=you@yourco.com
jira.apiToken=<your-jira-api-token>
# ── GitHub (optional) ────────────────────────────────────────────────────────
github.token=<your-github-token> # enables auto PR creation
# github.issuesRepo=owner/repo # enables GitHub Issues as ticket source
# ── Linear (optional) ────────────────────────────────────────────────────────
# linear.apiKey=<your-linear-key>
# ── Slack notifications (optional) ───────────────────────────────────────────
# slack.webhookUrl=https://hooks.slack.com/services/...
# ── Email notifications (optional) ───────────────────────────────────────────
# smtp.host=smtp.gmail.com
# smtp.port=587
# smtp.username=sender@example.com
# smtp.password=<app-specific-password>
# smtp.to=recipient@example.com
# ── Approver identity (optional) ─────────────────────────────────────────────
# sdlc.approver=Alice Chen
# sdlc.approver.role=senior-engineer
# ── RBAC: require a role for high-risk intents (optional) ────────────────────
# sdlc.require.role.EXECUTION_REQUEST=senior-engineer
# sdlc.require.role.BUG_FIX=engineer
# ── Coverage gate (optional) ─────────────────────────────────────────────────
# sdlc.coverage.minimum=0.80 # pipeline fails if line coverage drops below 80%
# ── Shared audit database for multi-developer teams (optional) ───────────────
# sdlc.db.url=jdbc:sqlite:/shared/drive/sdlc-audit.db
The config file is never committed to source control — it holds credentials. Your .gitignore should exclude sdlc-local.properties and sdlc.properties.
3. Running the Pipeline
Ticket from Jira
sdlc --ticket-id PROJ-42 --project /path/to/your/project
Ticket provided inline (no Jira required)
sdlc --ticket-id PROJ-42 \
--title "Add GET /api/users endpoint" \
--description "As a client I need to retrieve all users from the database." \
--project /path/to/your/project
Other common invocations
# Custom config file
sdlc --ticket-id PROJ-42 --project /path/to/project --config /path/to/sdlc-local.properties
# Force codebase rescan (skip cached index)
sdlc --ticket-id PROJ-42 --project /path/to/project --rescan
# Dry run — see the diff without applying anything
sdlc --ticket-id PROJ-42 --project /path/to/project --dry-run
What happens when you run
The pipeline proceeds through nine stages. At two points it stops and asks you to approve before continuing. Type yes to proceed or no to stop.
Ticket
→ Checkpoint 0 clarify open questions
→ Scan index the local codebase
→ Plan RAG + LLM generates structured plan
→ Validate hard validation gate (automated)
→ Role gate RBAC check (if configured)
→ Checkpoint 1 you review and approve the plan
→ CodeGen LLM reads files, writes implementations
→ Checkpoint 2 you review and approve the generated code
→ Apply files written to disk
→ Verify compile + test suite runs
→ Commit branch created, changes committed
→ PR GitHub PR opened (if github.token configured)
→ Audit full record written
4. Pipeline Stages Explained
Checkpoint 0 — Clarification
The LLM reads the ticket and produces a technical interpretation of the request, along with any open questions it cannot resolve from the ticket alone. You see this before any code is planned. If the ticket is ambiguous, this is where you catch it.
Scan
The platform indexes your codebase locally — controllers, services, models, dependencies — and builds a vector index for RAG retrieval. The index is cached; subsequent runs skip re-indexing unless you pass --rescan.
Plan generation
The LLM uses RAG to retrieve relevant parts of your codebase and generates a structured execution plan containing:
- A plain-English summary of the overall change
- A list of operations — each with an intent, a rationale, and the files it affects
- Constraints (things that must be true before code is written)
- Validation requirements (things that must be true after code is written)
Validation (hard gate)
An automated validator checks the plan before any human sees it. It verifies all operations have targets, no circular dependencies exist, and all referenced files are present or explicitly new. If validation fails, the pipeline stops immediately. There is no human bypass.
Role gate
If RBAC is configured, the platform checks whether the current approver's role satisfies the requirement for the detected intent type. If the role does not match, the pipeline stops with outcome REJECTED_BY_RBAC. See Section 10.
Checkpoint 1 — Plan review
The full plan is displayed in your terminal. You read it, then approve or reject. Things to look for:
- Does the plan match what the ticket asked for?
- Are the affected files correct?
- Does anything in the plan seem out of scope or risky?
If you reject, the pipeline stops. No code is generated. The rejection is recorded in the audit log.
Code generation
After plan approval, the LLM reads the actual current contents of every affected file and generates complete, working implementations. No stubs. No TODOs. It writes the file as it should look after the change.
Checkpoint 2 — Diff review
The generated code is displayed as a unified diff. You read it, then approve or reject. Things to look for:
- Does the generated code match the plan?
- Are there any issues a reviewer would flag in a PR?
- Is anything unexpected being changed?
If you pass --dry-run, the pipeline stops here without writing anything.
Apply
Generated file contents are written to disk. Nothing is applied before this point.
Verify
The platform runs your build and test suite based on the detected project type:
| Project type | Verifier command |
|---|---|
| Spring Boot / Maven | mvn clean compile test |
| Gradle | gradle build |
| Node / TypeScript | npm test |
| Python | pytest |
If the build fails, the pipeline stops with EXECUTION_FAILED. If sdlc.coverage.minimum is configured and coverage falls below the threshold, the pipeline also fails.
Commit, PR, and audit
On success, the platform:
- Creates a branch named
<ticket-id>(e.g.,PROJ-42) - Commits all generated files with message
[PROJ-42] Ticket Title - Opens a GitHub PR from that branch to
main(ifgithub.tokenis configured) - Writes a full audit record to
~/.sdlc/audit/ - Transitions the Jira ticket to "In Review" (if Jira is configured)
- Sends notifications if
--notifyis passed and Slack/email are configured
5. Project Type Support
The platform auto-detects your project type by looking for these files in the project root:
| Order | Files checked | Detected type |
|---|---|---|
| 1 | tsconfig.json and package.json | Node / TypeScript |
| 2 | requirements.txt or pyproject.toml | Python |
| 3 | build.gradle or build.gradle.kts | Gradle |
| 4 | pom.xml | Spring Boot / Maven |
| 5 | package.json (fallback) | Node / TypeScript |
To override detection:
sdlc --ticket-id PROJ-42 --project /path --project-type python
Accepted values: spring-boot, spring, maven, gradle, node-typescript, node, typescript, ts, nestjs, express, python, py.
To override only the build verifier independently of the scanner:
sdlc --ticket-id PROJ-42 --project /path --build-system gradle
6. Ticket Sources
Jira (default)
Configure jira.baseUrl, jira.email, and jira.apiToken. The platform fetches the ticket automatically.
sdlc --ticket-id PROJ-42 --project /path/to/project
Linear
Set linear.apiKey in your config. The platform auto-detects Linear when the key is present.
sdlc --ticket-id ENG-123 --project /path/to/project
# or explicitly:
sdlc --ticket-id ENG-123 --project /path/to/project --ticket-source linear
GitHub Issues
Set github.token and github.issuesRepo=owner/repo in your config.
sdlc --ticket-id 42 --project /path/to/project
# or explicitly:
sdlc --ticket-id 42 --project /path/to/project --ticket-source github
Manual (no ticket system)
Skip ticket ingestion entirely by providing the ticket inline. No credentials needed.
sdlc --ticket-id LOCAL-1 \
--title "Refactor UserService to use repository pattern" \
--description "Extract database calls from UserService into a UserRepository." \
--project /path/to/project
Auto-detection order
When --ticket-source is not specified, the platform selects in this order: Linear (if linear.apiKey is set) → GitHub Issues (if both github.token and github.issuesRepo are set) → Jira (fallback).
7. Audit Log
Every pipeline run — including rejections, failures, and dry runs — produces a complete audit record.
Location
~/.sdlc/audit/<TICKET-ID>-<YYYYMMDD-HHMMSS>.json
What is recorded
| Field | Description |
|---|---|
ticketId, ticketTitle | The ticket that was processed |
startedAt, completedAt | ISO 8601 timestamps |
outcome | Final outcome (see outcomes below) |
intentType | How the LLM classified the ticket |
planSummary | High-level plan description |
planOperations | All plan operations with intent, rationale, affected files |
planApprover | Name of the person who approved the plan |
codeApprover | Name of the person who approved the code |
generatedDiff | Full generated file contents |
executedOperations | List of files written to disk |
gitBranch, gitCommitSha | Branch and commit SHA |
prUrl | GitHub PR URL |
coverage | Line coverage %, covered lines, total lines, report path |
metrics | Wall clock duration, LLM model, token counts, estimated cost |
events | Timestamped log of every pipeline event |
validationErrors | Validation failures (if any) |
failureReason | Human-readable failure description |
Possible outcomes
| Outcome | What it means |
|---|---|
SUCCESS | Pipeline completed; code applied, verified, and committed |
DRY_RUN | Ran with --dry-run; diff generated but not applied |
REJECTED_BY_HUMAN | Developer rejected the plan at Checkpoint 1 |
ABORTED_AT_DIFF | Developer rejected the code at Checkpoint 2 |
REJECTED_BY_VALIDATION | Automated validation gate failed |
REJECTED_BY_RBAC | Approver role did not satisfy the configured requirement |
EXECUTION_FAILED | Build or test suite failed after applying changes |
PLAN_GENERATION_FAILED | LLM could not produce a valid plan |
NON_EXECUTABLE_INTENT | Ticket intent was analysis or investigation, not a code change |
Viewing audit records
# List the 20 most recent runs
sdlc --list-audits
# Show the full record for a ticket
sdlc --show-audit PROJ-42
Shared audit database
For multi-developer teams, point all instances at a shared SQLite database:
sdlc.db.url=jdbc:sqlite:/shared/drive/sdlc-audit.db
Audit JSON is written to both the local file and the shared database. The web dashboard can read from either.
8. Web Dashboard
sdlc --serve
# Open http://localhost:7070
List view
Shows all pipeline runs with summary stats (total runs, success rate, average duration, total cost) and a filterable table. Filters: ticket ID search, outcome dropdown, date range.
Detail view
Click any row to open the full audit record: ticket metadata and outcome, approver identities, git branch and commit SHA, PR link, LLM model and cost, code coverage, the full execution plan, and the generated diff file by file.
9. Compliance Reports
SOC2 Type II evidence report
# Single ticket (text)
sdlc --export-report PROJ-42
# Single ticket (PDF)
sdlc --export-pdf-report PROJ-42
# All tickets
sdlc --export-all
# All tickets since a date (PDF)
sdlc --export-all-pdf --since 2026-01-01
| Pipeline stage | SOC2 control | Evidence |
|---|---|---|
| Plan approval | CC6.6 Change Authorization | Plan approved by: [name] |
| Code review and approval | CC6.2 Separation of Duties | Code approved by: [name] |
| Build and test verification | CC8.1 Testing and QA | Tests passed; coverage X% |
| Audit trail | CC7.2 Audit Trail | Written to ~/.sdlc/audit/ |
HIPAA change management record
sdlc --export-hipaa-report PROJ-42
sdlc --export-hipaa-pdf-report PROJ-42
sdlc --export-all-hipaa
sdlc --export-all-hipaa-pdf --since 2026-01-01
| Pipeline stage | HIPAA section | Evidence |
|---|---|---|
| Change authorization | §164.308(a)(5) Security | Approved by: [name] |
| Separation of duties | §164.308(a)(3) Workforce | Code reviewed by: [name] |
| Build and test | §164.312(c)(1) Integrity | Tests passed; coverage X% |
| Audit trail | §164.312(b) Audit Controls | Written to ~/.sdlc/audit/ |
| Dual approval gate | §164.312(a)(1) Access Control | Pipeline enforces dual approval |
Output location
~/.sdlc/audit/reports/<TICKET-ID>-report.txt
~/.sdlc/audit/reports/<TICKET-ID>-report.pdf
~/.sdlc/audit/reports/<TICKET-ID>-hipaa.txt
~/.sdlc/audit/reports/<TICKET-ID>-hipaa.pdf
10. Role-Based Access Control
RBAC lets you require a specific approver role for certain types of changes. It is checked automatically after plan validation and before the plan is shown to the user.
Configuration
# Declare who is running the platform
sdlc.approver=Alice Chen
sdlc.approver.role=senior-engineer
# Require senior-engineer for new features and endpoints
sdlc.require.role.EXECUTION_REQUEST=senior-engineer
# Require any engineer for bug fixes
sdlc.require.role.BUG_FIX=engineer
Intent types
| Intent type | Typical ticket |
|---|---|
EXECUTION_REQUEST | New feature, new endpoint, new service |
BUG_FIX | Fix a defect, correct behavior |
ANALYSIS_REQUEST | Investigate or explain — no code change |
INVESTIGATION | Diagnose an issue |
NON_TECHNICAL | Documentation, process, not a code task |
Behavior
- If no requirement is configured for the detected intent type, any approver can proceed.
- If a requirement exists and the approver's role matches, the pipeline continues.
- If a requirement exists and the approver has no role, or the role does not match, the pipeline stops with
REJECTED_BY_RBAC. - The RBAC check result is recorded in the audit log.
Regardless of RBAC, the audit log always records planApprover and codeApprover. Identity comes from sdlc.approver in config, or falls back to the USER environment variable.
11. Notifications
Configuration
# Slack
slack.webhookUrl=https://hooks.slack.com/services/T.../B.../...
# Email
smtp.host=smtp.gmail.com
smtp.port=587
smtp.username=sender@example.com
smtp.password=<app-specific-password>
smtp.to=recipient@example.com
Enabling notifications
sdlc --ticket-id PROJ-42 --project /path/to/project --notify
What triggers a notification
Notifications are sent for three outcomes only: SUCCESS, EXECUTION_FAILED, and REJECTED_BY_VALIDATION. Rejections by the developer and dry runs do not send notifications.
SDLC Pipeline Result
Ticket: PROJ-42
Outcome: SUCCESS
PR: https://github.com/your-org/your-repo/pull/123
Commit: abc123def456...
Duration: 45.3s
Est. cost: $0.0234 USD
Notification failures (unreachable webhook, SMTP error) are logged as warnings and do not affect the pipeline outcome.
12. Metrics
sdlc --metrics
Aggregates statistics across all audit records in ~/.sdlc/audit/:
- Total runs — count of all pipeline executions
- Successful — count and percentage of
SUCCESSoutcomes - Per-outcome breakdown — count of each failure type
- Average duration — mean wall-clock time across successful runs (seconds)
- LLM models used — how many runs used each model
- Total tokens — aggregate prompt and completion tokens across all runs
- Total cost — sum of estimated LLM costs across all runs (USD)
- Coverage — average and minimum line coverage percentage across successful runs
13. CI/CD Integration
GitHub Actions
A ready-to-use workflow is included at .github/workflows/sdlc-platform.yml. Use --non-interactive to auto-approve both checkpoints — the human review happens in the PR the platform opens.
- name: Run SDLC pipeline
run: |
sdlc --ticket-id "${{ env.TICKET_ID }}" --project . --non-interactive
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
Exit codes
| Exit code | Meaning |
|---|---|
0 | SUCCESS or DRY_RUN |
1 | Any failure or rejection |
Jenkins
Run the platform as a shell step. Use --non-interactive and check the exit code. The platform returns 1 on any failure.
14. Docker
Image: ghcr.io/gbakalar/sdlc-platform:latest
Basic run
docker run --rm \
-v ~/.sdlc:/root/.sdlc \
-v /path/to/your/project:/project \
ghcr.io/gbakalar/sdlc-platform:latest \
--ticket-id PROJ-42 --project /project
With an explicit config path
docker run --rm \
-v ~/.sdlc:/root/.sdlc \
-v /path/to/your/project:/project \
ghcr.io/gbakalar/sdlc-platform:latest \
--ticket-id PROJ-42 --project /project --config /root/.sdlc/sdlc-local.properties
Volumes
| Mount | Purpose |
|---|---|
~/.sdlc:/root/.sdlc | Config file and audit log storage |
/path/to/project:/project | Target codebase |
15. CLI Reference
Pipeline
| Flag | Description |
|---|---|
--ticket-id ID | Ticket identifier to process |
--title "text" | Ticket title (skips Jira fetch when provided) |
--description "text" | Ticket description (used with --title) |
--project /path | Path to the target project root |
--config /path | Path to the config file |
--ticket-source jira|linear|github | Override ticket source auto-detection |
--project-type TYPE | Override project type auto-detection |
--build-system TYPE | Override build verifier independently |
--rescan | Force codebase rescan (ignore cached index) |
Pipeline control
| Flag | Description |
|---|---|
--dry-run | Generate and display diff without applying changes |
--non-interactive | Auto-approve both checkpoints (for CI) |
--no-git | Skip branch creation and commit |
--notify | Send Slack/email notification on completion |
Audit and history
| Flag | Description |
|---|---|
--list-audits | List the 20 most recent audit records |
--show-audit ID | Show the full audit record for a ticket |
--metrics | Show aggregate stats across all audits |
--serve | Start the web dashboard at http://localhost:7070 |
Compliance reports
| Flag | Description |
|---|---|
--export-report ID | Export SOC2 report (text) for one ticket |
--export-hipaa-report ID | Export HIPAA report (text) for one ticket |
--export-pdf-report ID | Export SOC2 report (PDF) for one ticket |
--export-hipaa-pdf-report ID | Export HIPAA report (PDF) for one ticket |
--export-all | Batch export SOC2 reports (text) |
--export-all-hipaa | Batch export HIPAA reports (text) |
--export-all-pdf | Batch export SOC2 reports (PDF) |
--export-all-hipaa-pdf | Batch export HIPAA reports (PDF) |
--since YYYY-MM-DD | Filter batch exports by date (inclusive) |
Utilities
| Flag | Description |
|---|---|
--version, -v | Print version and exit |
--help, -h | Print all flags and examples |
16. Config Reference
All properties go in ~/.sdlc/sdlc-local.properties unless --config specifies another path.
LLM
| Property | Description |
|---|---|
llm.anthropicApiKey | Anthropic API key (uses claude-sonnet-4-6) |
llm.openAiApiKey | OpenAI API key (uses gpt-4o) |
llm.ollamaBaseUrl | Ollama base URL for local embeddings (optional) |
Jira
| Property | Description |
|---|---|
jira.baseUrl | Jira instance URL (e.g., https://yourco.atlassian.net) |
jira.email | Jira account email |
jira.apiToken | Jira API token |
GitHub
| Property | Description |
|---|---|
github.token | GitHub personal access token (enables auto PR creation) |
github.issuesRepo | GitHub repo for ticket ingestion (e.g., owner/repo) |
Linear
| Property | Description |
|---|---|
linear.apiKey | Linear API key |
Notifications
| Property | Description |
|---|---|
slack.webhookUrl | Slack Incoming Webhook URL |
smtp.host | SMTP server hostname |
smtp.port | SMTP port (default: 587) |
smtp.username | SMTP username |
smtp.password | SMTP password |
smtp.to | Notification recipient email |
Approver and RBAC
| Property | Description |
|---|---|
sdlc.approver | Approver display name (recorded in audit) |
sdlc.approver.role | Approver role for RBAC checks |
sdlc.require.role.<INTENT_TYPE> | Required approver role for a specific intent type |
Quality and audit
| Property | Description |
|---|---|
sdlc.coverage.minimum | Minimum required line coverage (0.0–1.0); pipeline fails if below this |
sdlc.db.url | SQLite JDBC URL for shared audit database |
17. Troubleshooting
"could not determine latest release" during install
The install script fetches the latest tag from the GitHub API. Check your internet connection. If you are behind a proxy, set https_proxy before running the script.
Pipeline fails immediately with "config validation failed"
The platform validates the config on startup. Check that at least one LLM key (llm.anthropicApiKey or llm.openAiApiKey) is present, Jira config is complete if Jira is your ticket source, and there are no trailing spaces in property values.
"REJECTED_BY_VALIDATION" on every run
The plan validator found a problem. Check the validationErrors field in the audit record (sdlc --show-audit TICKET-ID). Common causes: ticket description is too vague (add more detail to --description), or the LLM hallucinated a file path (run --rescan to refresh the index).
Build fails after apply
The generated code has a compile or test error. The failureReason field in the audit record has the verifier output. Common causes: project type misdetected (use --project-type to override), or a stale codebase index (try --rescan).
No GitHub PR is created
github.token must be set in config and the local repo must have a main branch and a configured remote. The platform logs a warning and continues if PR creation fails.
Jira ticket not transitioning to "In Review"
The platform looks for a transition named "In Review" in your Jira workflow. If your workflow uses a different name, the transition is skipped and a warning is logged. The pipeline still completes successfully.
Notifications not arriving
- Verify
slack.webhookUrlis the full webhook URL including the path. - For Gmail, use an App Password rather than your account password.
- Check the
eventsarray in the audit JSON — it includes notification delivery logs.
Web dashboard shows no data
The dashboard reads from ~/.sdlc/audit/. Confirm that directory contains .json files. If you configured sdlc.db.url, pass the same --config file to --serve so the dashboard knows where the database is.