An open-source operating system for AI software factories

Your business changes. Your software should change with it.

Build and keep improving software around the way your company works. Soda OS brings AI coding agents, shared projects and review into a software factory you control.

Build internal tools for requests, approvals, onboarding and other company workflows—with your own rules and permissions. Explore the OS architecture and compare infrastructure.

Follow the work as it happens.

See plans, findings, corrections and decisions in your project’s feed. Answer a question where it matters, while the factory keeps the work moving.

Onboarding · project feedThe brief
HR team’S REQUEST
New starters keep arriving without a laptop, a badge or a first-week plan. Build HR one place to assign the jobs and see what’s missing before day one.
  • Enter each starter, manager and start date
  • Assign checklist jobs to IT, Facilities and managers
  • Remind owners and share what is ready for day one

Uses the company’s existing staff sign-in.

Direction accepted
company / software3 ready · 0 / 14 merged
Explore the evidence & issue plan

Built around the way your company works

Software for your department's work.

Your approval rules, terminology and exceptions belong in your software. Start with one workflow, then keep improving it as the business changes.

View CanLangBack to app
EquipmentRequests.canExcerpt

Approval and recorded delivery

When
 crud Equipment by=coordinator fields=name,category,active delete=none
 crud Request by=members fields=equipment,reason when=row.requested_by==actor and row.status==requested delete=none
 # Review another teammate's request against the equipment catalogue.
 scenario approve(request:Request) by=reviewer
  require request.status==requested and request.requested_by!=actor
  require request.equipment.active
  do set request {status=approved,approved_by=actor,approved_at=now}
 # Record the physical asset when approved equipment reaches the requester.
 scenario deliver(request:Request,asset_tag:text) by=coordinator
  require request.status==approved and trim(asset_tag)!=""
  do set request {status=delivered,asset_tag=trim(asset_tag),delivered_at=now}

Equipment · App preview

Equipment
EQ-1042 · Avery

Standing desk

Approved
Alex approved14 Oct · details locked
Asset tag · 15 OctDESK-001
Delivered

Illustrative application interface · sample records.

Operations

Equipment requests

Keep catalogue selection, requests, separate approval and recorded delivery connected.

One rule. A reviewer can approve another person's request; self-approval is refused.

Next change. Add a separate Finance approval above an illustrative €1,000 threshold.

Explore equipment requests →
View CanLangBack to app
Onboarding.canExcerpt

Task completion and reassignment

When
 crud Starter by=hr fields=name,employee,start_date,department delete=none
 crud Task by=hr fields=starter,title,responsible,due_date when=not row.done delete=none
 # The teammate responsible for a task records its completion.
 scenario complete(task:Task,note:text?) by=members
  require task.responsible==actor and not task.done
  do set task {done=true,completed_at=now,completion_note=note}
 # HR can hand unfinished work to another teammate.
 scenario reassign(task:Task,responsible:user) by=hr
  require not task.done
  do set task {responsible}

Onboarding · App preview

Onboarding

Sam

Operations · Starts 8 Mar
1 / 3complete
  • Prepare equipmentAlex · 5 Mar · Unfinished
  • Read safety handbookSam · 8 Mar · Completed
  • Welcome sessionTeam lead · 18 Mar · Unfinished

Illustrative application interface · sample records.

HR

Employee onboarding

Make each joining task's owner, deadline and completion visible.

One rule. Only the current assignee completes their unfinished task.

Next change. Align unfinished relative deadlines with the start date, protecting fixed dates and completed work.

Explore employee onboarding →
View CanLangBack to app
Expenses.canExcerpt

Approval and payment records

When
 crud CostCentre by=finance fields=code,name,active delete=none
 crud Expense by=members fields=purpose,amount,cost_centre update=none delete=none
 # A reviewer approves someone else's positive expense claim.
 scenario approve(expense:Expense,note:text?) by=reviewer
  require expense.status==submitted and expense.submitted_by!=actor
  require expense.cost_centre.active
  do set expense {status=approved,decision_note=note,approved_by=actor,approved_at=now}
 # Finance records a payment only after the claim is approved.
 scenario record_payment(expense:Expense,reference:text) by=finance
  require expense.status==approved and trim(reference)!=""
  do set expense {status=paid,payment_reference=trim(reference),paid_at=now}

Expenses · App preview

Expenses
EXP-0085 · Sam

Client travel

€85
Cost centre
CLIENT
Review
Alex · Approved
External payment ref.TRAVEL-001
Paid

Payment recorded only; no money transferred.

Illustrative application interface · sample records.

Finance

Expense approvals

Give submitted expenses a clear review decision and record of external payment.

One rule. Approval belongs to a separate reviewer; submitted claim details stay protected.

Next change. Return a mistaken claim with a reason and review one linked replacement while retaining the original.

Explore expense approvals →
View CanLangBack to app
Maintenance.canExcerpt

Work notes and resolution

When
 crud Location by=technician fields=name,building,floor delete=none
 crud Ticket by=members fields=location,issue,priority update=none delete=none
 # Append a visit or diagnostic note while a ticket is open.
 scenario record_work(ticket:Ticket,note:text) by=technician
  require ticket.status==open and trim(note)!=""
  do create WorkNote {parent=ticket,note=trim(note)} as work_note
 # Resolve the issue with a description of the repair.
 scenario resolve(ticket:Ticket,resolution:text) by=technician
  require ticket.status==open and trim(resolution)!=""
  do set ticket {status=resolved,resolution=trim(resolution),resolved_by=actor,resolved_at=now}

Maintenance · App preview

Maintenance
MT-042 · Sam · 6 MarOpen

Air conditioning is not cooling

Jordan · Work note

Supply air is warm. Checking cooling controls.

Illustrative application interface · sample records.

Facilities

Maintenance tickets

Turn reported issues into a queue technicians can investigate and resolve.

One rule. Employees see their own reports; technicians can read the maintenance queue.

Next change. Link a new occurrence to an earlier resolved ticket at the same location, preserving both histories and access.

Explore maintenance tickets →

Illustrative applications · Each department defines and accepts its own business requirements.

Inside the factory

Follow one request all the way to the app.

Choose your department. Follow its request through an accepted direction, a dependency plan, CanLang source, review and integration, then try the matching application example.

  1. 01

    Define and plan

    Describe the business outcome and approve the proposed direction. Soda turns it into authorized work in Forgejo, with prerequisites, access and resource limits.

  2. 02

    Build

    A coding agent implements the ready work in the project environment. Separate accounts and checkouts keep each attempt distinct while the Project retains its tools and services.

  3. 03

    Review and correct

    A separate agent session reviews the candidate alongside required automated checks. Each revised candidate needs current verification evidence; another independent review follows evidence and repository policy.

  4. 04

    Merge and continue

    Verified changes merge under repository policy, including human review where required. Soda reassesses dependent work and continues within the approved limits.

Required checks and repository policy govern integration, including human approval where required. Application deployment and business acceptance remain distinct.

Source-based example · Operations · Equipment requests
“Let employees request catalogue equipment. A reviewer must approve someone else’s request before Operations records delivery and an asset tag.”

An illustrative journey based on Soda OS’s documented workflow and the linked CanLang example. The request, work items and review cases are examples, not a recorded factory run.

1 / 6 · Operations owns the direction

Agree on equipment, approval and delivery.

Operations opens New Project and answers “What do you want to build?” Explore ideas develops the experience. In “Review your product direction”, Operations accepts the rules or asks for changes before implementation.

What carries forward

An accepted application direction, with people, records and refusal cases. Material questions return to Operations.

Illustrative accepted direction

Illustrative accepted direction

Avery requests a standing desk

  1. One catalogue and a personal request list

    Employees choose equipment, explain the business reason and follow their own requests. Reviewers and Operations can read the queue.

  2. Another person approves

    A reviewer approves another person’s eligible request for active equipment. Self-approval and a second approval are refused.

  3. Operations records delivery

    A coordinator records delivery only after approval, with a nonempty asset tag. Approved request details and completed delivery records stay protected.

Illustrative workflow artifact from the selected department journey.

2 / 6 · Soda coordinates the work

Give the workflow a plan with prerequisites.

Operations authorizes a finite planning allowance and chooses a repository. Soda creates native Forgejo work items with acceptance criteria and explicit dependencies. Execution needs repository authorization, accounts and capacity.

What carries forward

Accepted work-item criteria and prerequisite outcomes. Unresolved dependencies and unanswered requirements keep work from advancing.

Illustrative native work items

Illustrative native work items

From catalogue to an accountable handover

  1. Define equipment, requests and access

    Store catalogue availability, request ownership and status. Employees read their own requests; reviewers and coordinators read the queue.

  2. Implement guarded approval and delivery

    Depends on records and permissions. Check the reviewer’s identity and request state; require approval and an asset tag before delivery.

  3. Connect screens and check outcomes

    Depends on the allowed operations. Test Avery’s request, Alex’s approval and the coordinator’s delivery, alongside unrelated-reader and self-approval refusals.

Illustrative workflow artifact from the selected department journey.

3 / 6 · The coding agent implements

Build the agreed request-to-delivery rules.

Soda assesses readiness and prepares the persistent Project and assigned checkout. The coding agent implements the accepted work with repository context and authorized access, then reports a candidate and evidence. Soda OS publishes the pull request.

What carries forward

A candidate pull request at an exact revision. Spaces shows agent activity and intervention needs alongside Forgejo.

EquipmentRequests.can · first-version source excerpt

Catalogue, separate approval and delivery

Given
 role reviewer
 role coordinator
 Equipment {
  name:text trim max=120 label="Equipment",
  category:enum(computer,furniture,accessory) label="Category",
  active:bool=true label="Available to request"
 }
 Request {
  equipment:Equipment label="Equipment",
  reason:text trim max=500 label="Business reason",
  requested_by:user server=actor label="Requested by",
  status:enum(requested,approved,delivered)=requested label="Status",
  approved_by:user? label="Approved by",
  approved_at:datetime? label="Approved at",
  delivered_at:datetime? label="Delivered at",
  asset_tag:text? label="Asset tag"
 }
 policy Equipment read=members
 policy Request read=members where=row.requested_by==actor
 policy Request read=reviewer
 policy Request read=coordinator
 invariant Request: trim(row.reason)!=""
 lock Request fields=equipment,reason,requested_by when=row.status!=requested
 lock Request fields=approved_by,approved_at when=row.status!=requested
 lock Request fields=status,delivered_at,asset_tag when=row.status==delivered
When
 crud Equipment by=coordinator fields=name,category,active delete=none
 crud Request by=members fields=equipment,reason when=row.requested_by==actor and row.status==requested delete=none
 # Review another teammate's request against the equipment catalogue.
 scenario approve(request:Request) by=reviewer
  require request.status==requested and request.requested_by!=actor
  require request.equipment.active
  do set request {status=approved,approved_by=actor,approved_at=now}
 # Record the physical asset when approved equipment reaches the requester.
 scenario deliver(request:Request,asset_tag:text) by=coordinator
  require request.status==approved and trim(asset_tag)!=""
  do set request {status=delivered,asset_tag=trim(asset_tag),delivered_at=now}
4 / 6 · Another agent checks the candidate

Check identity as well as the reviewer role.

A separate agent session reviews the exact candidate alongside required checks. Findings return to the coding role; revised candidates receive fresh checks, with further independent review when evidence or repository policy requires it.

What carries forward

Evidence belongs to the revised candidate. These are illustrative review expectations, rather than a report of a completed factory run.

Illustrative review and correction

Illustrative review and correction

A reviewer must not approve their own request

  1. Finding: a role check would allow self-approval

    If Avery also held the reviewer role, checking that role alone would permit Avery to approve the standing desk request.

  2. Correction: check identity, state and availability

    Require an awaiting request from another person and active catalogue equipment. Delivery separately requires approval and a valid asset tag.

  3. Fresh review: exercise permitted and refused paths

    Alex can approve Avery’s request; Avery cannot approve it. Refuse repeated approval, delivery before approval and changes to approved or delivered details. An unrelated employee cannot read Avery’s request.

Illustrative workflow artifact from the selected department journey.

5 / 6 · Forgejo policy governs integration

Integrate when current evidence satisfies policy.

Soda merges when required checks and review pass for the exact candidate and repository policy permits it. Required human approval is part of that path. Changed or missing evidence prevents integration.

What carries forward

Confirmed integration lets Soda reassess dependent work. Application deployment remains a separate action.

Integration conditions

Integration conditions

The revision, evidence and native outcome agree

  1. The candidate still matches

    The pull request’s current revision is the revision that was checked and reviewed.

  2. Required evidence is current

    Checks, review and any required human approval satisfy the repository’s policy.

  3. Forgejo confirms integration

    The native merge and work-item outcome are recorded before dependent work is reassessed.

Illustrative workflow artifact from the selected department journey.

6 / 6 · Operations and employees assess the result

Follow Avery’s request through the handover.

Employees and Operations assess the agreed workflow: Avery requests a standing desk, Alex approves it and a coordinator records delivery. The larger CanLang source covers that first version. The compact browser example lets you try request and approval rules.

What carries forward

A workflow assessed against the department’s acceptance outcomes. The next agreed improvement enters the same persistent Project.

Try the equipment approval example
View CanLangBack to app
EquipmentRequests.canExcerpt

Approval and recorded delivery

When
 crud Equipment by=coordinator fields=name,category,active delete=none
 crud Request by=members fields=equipment,reason when=row.requested_by==actor and row.status==requested delete=none
 # Review another teammate's request against the equipment catalogue.
 scenario approve(request:Request) by=reviewer
  require request.status==requested and request.requested_by!=actor
  require request.equipment.active
  do set request {status=approved,approved_by=actor,approved_at=now}
 # Record the physical asset when approved equipment reaches the requester.
 scenario deliver(request:Request,asset_tag:text) by=coordinator
  require request.status==approved and trim(asset_tag)!=""
  do set request {status=delivered,asset_tag=trim(asset_tag),delivered_at=now}

Equipment · App preview

Equipment
EQ-1042 · Avery

Standing desk

Approved
Alex approved14 Oct · details locked
Asset tag · 15 OctDESK-001
Delivered

Illustrative application interface · sample records.

Read the application outcomes

Requested → Approved → Delivered

  • Avery follows a personal request

    Choose catalogue equipment and explain the reason. Ordinary employees cannot read another person’s requests.

  • Alex approves; Operations records delivery

    Approval protects the request details. A nonempty asset tag records the handover, with completed delivery fields preserved.

  • The next requirement stays with this app

    Operations can later add Finance approval above €1,000 through a separately reviewed change. That continuation has its own supporting source; it does not extend the compact demo.

Source-based example · HR · Onboarding tasks
“Give every onboarding task an owner. HR needs the full list; teammates need their own tasks and a way to complete them.”

An illustrative journey based on Soda OS’s documented workflow and the linked CanLang example. The request, work items and review cases are examples, not a recorded factory run.

1 / 6 · HR owns the direction

Agree on what good onboarding looks like.

Open New Project and answer “What do you want to build?” Explore ideas turns the request into a direction. HR uses “Review your product direction” to accept the experience or ask for changes.

What carries forward

An accepted product direction. Material questions return to HR instead of becoming hidden assumptions.

Example accepted direction

Example accepted direction

Onboarding tasks, with clear ownership

  1. HR assigns and follows work

    Create tasks, choose a responsible teammate and see the full list.

  2. Teammates see their own tasks

    Only the assigned person can complete a task.

  3. Completed tasks keep their history

    Lock the title and owner after completion. Keep deletion unavailable.

Illustrative workflow artifact from the selected department journey.

2 / 6 · Soda coordinates the work

Turn the direction into work with prerequisites.

Authorize a finite planning allowance and choose a repository. Soda generates native Forgejo work items with acceptance criteria and explicit dependencies. Execution still needs the repository’s authorization, accounts and capacity.

What carries forward

Accepted issue criteria and prerequisite outcomes. Work waits for unresolved dependencies or unanswered requirements.

Example native work items

Example native work items

A dependency plan for the same request

  1. Define the Task record and access

    Store title, responsible person and completion state. HR reads all tasks; teammates read their own.

  2. Implement assignment and completion

    Depends on the record and access rules. HR edits unfinished tasks; only the assignee completes.

  3. Connect the form and task list

    Depends on the record and operations. Verify the accepted behavior for HR and teammates.

Illustrative workflow artifact from the selected department journey.

3 / 6 · The coding agent implements

Build against the accepted rules.

Soda assesses readiness and prepares the repository’s persistent Project and assigned coding checkout. The selected coding agent receives the accepted issue, repository context and authorized account access, then reports the candidate and evidence. Soda OS publishes the pull request.

What carries forward

A candidate pull request at an exact revision. Spaces makes live agent activity and intervention needs visible alongside Forgejo.

Onboarding.can · source excerpt

The task’s completion rule

Given
 role hr
 Task { title:text trim, responsible:user, done:bool=false }
 policy Task read=members where=row.responsible==actor
 policy Task read=hr
 lock Task fields=title,responsible when=row.done
When
 crud Task by=hr fields=title,responsible when=not row.done delete=none
 # Mark your assigned onboarding task complete.
 scenario complete(task:Task) by=members
  require task.responsible==actor and not task.done
  do set task {done=true}
4 / 6 · Another agent checks the candidate

Check the behavior, then correct and review again.

A separate agent session reviews the exact candidate alongside required checks. Findings return to the coding role; revised candidates receive fresh checks, with further independent review when evidence or repository policy requires it.

What carries forward

Findings and review evidence tied to the candidate revision. An agent saying “done” does not establish a completed change.

Illustrative review and correction

Illustrative review and correction

Membership alone must not allow completion

  1. Finding: membership would be too broad

    If a candidate checked only membership, Alex could complete Sam’s task. That would violate HR’s accepted requirement.

  2. Correction: check assignment and status

    The coding role adds the responsible-person check and requires the task to be unfinished, as in the source above.

  3. Fresh review: test all three outcomes

    Sam can complete Sam’s unfinished task; Alex is refused; HR cannot change a completed task’s title or owner. Verify these expectations on the revised candidate.

Illustrative workflow artifact from the selected department journey.

5 / 6 · Forgejo policy governs integration

Integrate when the current policy permits it.

Soda merges automatically when required review and checks pass for the exact candidate and repository policy permits it. If policy requires human approval, that approval is part of the path. Changed or missing evidence prevents integration.

What carries forward

Confirmed integration lets Soda reassess dependent work. Merge and application deployment remain separate actions.

Integration conditions

Integration conditions

The candidate must satisfy all three

  1. The revision still matches

    The pull request’s current candidate is the revision that was checked and reviewed.

  2. Required evidence is current

    The required checks, review and any required human approval satisfy the repository’s rules.

  3. Native merge is confirmed

    Forgejo records the integration and corresponding issue outcome. Creating a PR is not a merge.

Illustrative workflow artifact from the selected department journey.

6 / 6 · HR and teammates use the workflow

One app connects assignment and progress.

The same CanLang source describes the records, access rules, completion action and screen. Try the matching browser example: assign a task as HR, switch to its responsible teammate and complete it.

What carries forward

A tool shaped around the department’s work. The next accepted improvement enters the same factory process.

Try the onboarding example
View CanLangBack to app
Onboarding.canExcerpt

Task completion and reassignment

When
 crud Starter by=hr fields=name,employee,start_date,department delete=none
 crud Task by=hr fields=starter,title,responsible,due_date when=not row.done delete=none
 # The teammate responsible for a task records its completion.
 scenario complete(task:Task,note:text?) by=members
  require task.responsible==actor and not task.done
  do set task {done=true,completed_at=now,completion_note=note}
 # HR can hand unfinished work to another teammate.
 scenario reassign(task:Task,responsible:user) by=hr
  require not task.done
  do set task {responsible}

Onboarding · App preview

Onboarding

Sam

Operations · Starts 8 Mar
1 / 3complete
  • Prepare equipmentAlex · 5 Mar · Unfinished
  • Read safety handbookSam · 8 Mar · Completed
  • Welcome sessionTeam lead · 18 Mar · Unfinished

Illustrative application interface · sample records.

Read the application outcomes

Read the safety handbook → Sam → Complete

  • HR has the overview

    Assign work and update unfinished tasks from the same list.

  • Sam has a clear next action

    See assigned tasks and mark them complete. Alex cannot complete Sam’s work.

  • The rule stays with the record

    Completed titles and owners stay locked. The browser example mirrors these rules with local page state.

Source-based example · Finance · Expense approvals
“Let teammates submit expenses with a purpose and amount. Reviewers need a shared approval list, and nobody should approve their own claim.”

An illustrative journey based on Soda OS’s documented workflow and the linked CanLang example. The request, work items and review cases are examples, not a recorded factory run.

1 / 6 · Finance owns the direction

Agree on a clear expense approval process.

Finance opens New Project and answers “What do you want to build?” Explore ideas develops the request: Sam submits Client travel for EUR 85.00; a separate reviewer approves it. Finance accepts or changes the experience in “Review your product direction”.

What carries forward

An accepted expense workflow. Material questions return to Finance instead of becoming hidden assumptions.

Example accepted direction

Example accepted direction

Expense claims, with separate approval

  1. Capture the claim accurately

    Store purpose, exact money amount, submitter and status. Require a positive amount; employees read their own claims and reviewers read the review queue.

  2. Keep approval independent

    Only a reviewer approves a submitted claim. Block self-approval even when the submitter also has the reviewer role.

  3. Preserve the approved claim

    Block repeated approval and lock purpose, amount and submitter after approval. Keep claim updates and deletion unavailable.

Illustrative workflow artifact from the selected department journey.

2 / 6 · Soda coordinates the work

Give each approval requirement a prerequisite.

Authorize a finite planning allowance and choose a repository. Soda creates native Forgejo work items with acceptance criteria and explicit dependencies. Execution needs the repository’s authorization, accounts and capacity.

What carries forward

Accepted issue criteria and prerequisite outcomes. Unresolved dependencies or unanswered requirements interrupt the work.

Example native work items

Example native work items

A dependency plan for Sam’s claim

  1. Define the Expense record and access

    Store exact money and the submitting actor. Require positive amounts, employee access to own claims and reviewer access to the queue.

  2. Implement submission and approval

    Depends on the record and access rules. Accept submissions; require reviewer role, submitted status and a different submitter before approval.

  3. Connect the claim form and review list

    Depends on records and operations. Check EUR 85.00 stays exact, another reviewer can approve, and self-approval and repeated approval are refused.

Illustrative workflow artifact from the selected department journey.

3 / 6 · The coding agent implements

Keep the expense policy with the claim.

Soda assesses readiness and prepares the repository’s persistent Project and assigned coding checkout. The selected coding agent receives the accepted issue, repository context and authorized account access, then reports the candidate and evidence. Soda OS publishes the pull request.

What carries forward

A candidate pull request at an exact revision. Spaces shows live agent activity and intervention needs alongside Forgejo.

Expenses.can · source excerpt

Positive amounts and independent approval

Given
 role reviewer
 Expense { purpose:text trim, amount:money, submitted_by:user server=actor, status:enum(submitted,approved)=submitted }
 policy Expense read=members where=row.submitted_by==actor
 policy Expense read=reviewer
 invariant Expense: row.amount.minor>0
 lock Expense fields=purpose,amount,submitted_by when=row.status==approved
When
 crud Expense by=members fields=purpose,amount update=none delete=none
 # Approve a submitted expense from another teammate.
 scenario approve(expense:Expense) by=reviewer
  require expense.status==submitted and expense.submitted_by!=actor
  do set expense {status=approved}
4 / 6 · Another agent checks the candidate

Catch self-approval, then review the correction.

A separate agent session reviews the exact candidate alongside required checks. Findings return to the coding role; revised candidates receive fresh checks, with further independent review when evidence or repository policy requires it.

What carries forward

Findings and evidence belong to the revised candidate. These cases illustrate review expectations rather than report a completed run.

Illustrative review and correction

Illustrative review and correction

A reviewer role alone is insufficient

  1. Finding: Sam could approve Sam’s claim

    If a candidate checked only the reviewer role, Sam could approve their own EUR 85.00 expense. That violates Finance’s accepted requirement.

  2. Correction: require a different submitter

    The coding role checks submitted status and submitter identity, alongside reviewer authority and the positive-amount invariant shown above.

  3. Fresh review: exercise the accepted cases

    Alex as reviewer can approve Sam’s submitted claim; Sam as reviewer cannot. Refuse ordinary employee approval, repeat approval, zero and negative amounts. Preserve EUR 85.00 exactly and lock approved fields.

Illustrative workflow artifact from the selected department journey.

5 / 6 · Forgejo policy governs integration

Integrate when the current policy permits it.

Soda merges automatically when required review and checks pass for the exact candidate and repository policy permits it. When policy requires human approval, that approval is part of the path. Changed or missing evidence prevents integration.

What carries forward

Confirmed integration lets Soda reassess dependent work. Merge and application deployment remain separate actions.

Integration conditions

Integration conditions

The candidate must satisfy all three

  1. The revision still matches

    The pull request’s current candidate is the revision that was checked and reviewed.

  2. Required evidence is current

    Required checks, review and any required human approval satisfy the repository’s rules.

  3. Native merge is confirmed

    Forgejo records integration and the corresponding issue outcome. A published pull request alone does not establish integration.

Illustrative workflow artifact from the selected department journey.

6 / 6 · Finance and employees use the workflow

Connect expense submission and independent review.

The same CanLang source describes the claim, access rules, approval action and screen. Try the matching browser example: submit Client travel as Sam, then switch to Alex as reviewer to approve EUR 85.00.

What carries forward

A tool shaped around Finance’s work. The next accepted improvement enters the same factory process.

Try the expense example
View CanLangBack to app
Expenses.canExcerpt

Approval and payment records

When
 crud CostCentre by=finance fields=code,name,active delete=none
 crud Expense by=members fields=purpose,amount,cost_centre update=none delete=none
 # A reviewer approves someone else's positive expense claim.
 scenario approve(expense:Expense,note:text?) by=reviewer
  require expense.status==submitted and expense.submitted_by!=actor
  require expense.cost_centre.active
  do set expense {status=approved,decision_note=note,approved_by=actor,approved_at=now}
 # Finance records a payment only after the claim is approved.
 scenario record_payment(expense:Expense,reference:text) by=finance
  require expense.status==approved and trim(reference)!=""
  do set expense {status=paid,payment_reference=trim(reference),paid_at=now}

Expenses · App preview

Expenses
EXP-0085 · Sam

Client travel

€85
Cost centre
CLIENT
Review
Alex · Approved
External payment ref.TRAVEL-001
Paid

Payment recorded only; no money transferred.

Illustrative application interface · sample records.

Read the application outcomes

Client travel → EUR 85.00 → Approved

  • Sam sees Sam’s claims

    Submit a positive exact money amount and follow its status in the personal list.

  • Alex reviews the queue

    Approve another employee’s submitted claim. Reviewer authority never permits self-approval.

  • Approval preserves the details

    Repeated approval is refused and approved fields stay locked. The browser example mirrors the rules with local page state and a reset control.

Source-based example · Facilities · Maintenance tickets
“Let teammates report maintenance issues with a location. Technicians need a shared queue and a way to mark open tickets resolved.”

An illustrative journey based on Soda OS’s documented workflow and the linked CanLang example. The request, work items and review cases are examples, not a recorded factory run.

1 / 6 · Facilities owns the direction

Agree on a clear path from report to resolution.

Facilities opens New Project and answers “What do you want to build?” Explore ideas develops the request: Sam reports that Floor 2’s air conditioning is not cooling; a technician resolves the ticket. Facilities accepts or changes the experience in “Review your product direction”.

What carries forward

An accepted maintenance workflow. Material questions return to Facilities instead of becoming hidden assumptions.

Example accepted direction

Example accepted direction

Maintenance reports, with a technician queue

  1. Capture a useful report

    Keep location, issue, reporter and status together. New reports start open and record the employee who submitted them.

  2. Give each role the right view

    Employees read their own reports. Technicians read the full maintenance queue.

  3. Let technicians resolve open tickets

    Require the technician role and open status. Block repeated resolution, lock resolved details and keep ticket updates and deletion unavailable.

Illustrative workflow artifact from the selected department journey.

2 / 6 · Soda coordinates the work

Plan the report, queue and resolution in order.

Authorize a finite planning allowance and choose a repository. Soda creates native Forgejo work items with acceptance criteria and explicit dependencies. Execution needs the repository’s authorization, accounts and capacity.

What carries forward

Accepted issue criteria and prerequisite outcomes. Unresolved dependencies or unanswered requirements interrupt the work.

Example native work items

Example native work items

A dependency plan for the Floor 2 report

  1. Define the Ticket record and access

    Store location, issue, reporting actor and open status. Employees read their own reports; technicians read the full queue.

  2. Implement reporting and resolution

    Depends on the record and access rules. Accept reports; require technician authority and open status before resolving a ticket.

  3. Connect the reporting form and queue

    Depends on records and operations. Verify Sam’s own-ticket view, the technician’s full queue and refusal of employee or repeated resolution.

Illustrative workflow artifact from the selected department journey.

3 / 6 · The coding agent implements

Make resolution follow the ticket’s rules.

Soda assesses readiness and prepares the repository’s persistent Project and assigned coding checkout. The selected coding agent receives the accepted issue, repository context and authorized account access, then reports the candidate and evidence. Soda OS publishes the pull request.

What carries forward

A candidate pull request at an exact revision. Spaces shows live agent activity and intervention needs alongside Forgejo.

Maintenance.can · source excerpt

Own reports, shared queue and guarded resolution

Given
 role technician
 Ticket { location:text trim, issue:text trim, reported_by:user server=actor, status:enum(open,resolved)=open }
 policy Ticket read=members where=row.reported_by==actor
 policy Ticket read=technician
 lock Ticket fields=location,issue,reported_by when=row.status==resolved
When
 crud Ticket by=members fields=location,issue update=none delete=none
 # Resolve an open maintenance ticket.
 scenario resolve(ticket:Ticket) by=technician
  require ticket.status==open
  do set ticket {status=resolved}
4 / 6 · Another agent checks the candidate

Check who can resolve, and when.

A separate agent session reviews the exact candidate alongside required checks. Findings return to the coding role; revised candidates receive fresh checks, with further independent review when evidence or repository policy requires it.

What carries forward

Findings and evidence belong to the revised candidate. These cases illustrate review expectations rather than report a completed run.

Illustrative review and correction

Illustrative review and correction

Reporting an issue does not authorize resolution

  1. Finding: an employee could resolve a report

    If a candidate allowed any member to resolve a ticket, Sam could close the Floor 2 report without technician authority. That violates Facilities’ accepted requirement.

  2. Correction: guard the role and state

    The coding role restricts resolution to technicians and requires an open ticket, as in the source above.

  3. Fresh review: exercise the accepted cases

    A technician can resolve Sam’s open report; Sam as employee cannot. Refuse a second resolution and changes to resolved details. Verify employees see their own reports while technicians see the full queue.

Illustrative workflow artifact from the selected department journey.

5 / 6 · Forgejo policy governs integration

Integrate when the current policy permits it.

Soda merges automatically when required review and checks pass for the exact candidate and repository policy permits it. When policy requires human approval, that approval is part of the path. Changed or missing evidence prevents integration.

What carries forward

Confirmed integration lets Soda reassess dependent work. Merge and application deployment remain separate actions.

Integration conditions

Integration conditions

The candidate must satisfy all three

  1. The revision still matches

    The pull request’s current candidate is the revision that was checked and reviewed.

  2. Required evidence is current

    Required checks, review and any required human approval satisfy the repository’s rules.

  3. Native merge is confirmed

    Forgejo records integration and the corresponding issue outcome. A published pull request alone does not establish integration.

Illustrative workflow artifact from the selected department journey.

6 / 6 · Facilities and employees use the workflow

Turn Sam’s report into a resolved ticket.

The same CanLang source describes the ticket, access rules, resolution action and screen. Try the matching browser example: report Floor 2’s air conditioning issue as Sam, then switch to the technician to resolve it.

What carries forward

A tool shaped around Facilities’ work. The next accepted improvement enters the same factory process.

Try the maintenance example
View CanLangBack to app
Maintenance.canExcerpt

Work notes and resolution

When
 crud Location by=technician fields=name,building,floor delete=none
 crud Ticket by=members fields=location,issue,priority update=none delete=none
 # Append a visit or diagnostic note while a ticket is open.
 scenario record_work(ticket:Ticket,note:text) by=technician
  require ticket.status==open and trim(note)!=""
  do create WorkNote {parent=ticket,note=trim(note)} as work_note
 # Resolve the issue with a description of the repair.
 scenario resolve(ticket:Ticket,resolution:text) by=technician
  require ticket.status==open and trim(resolution)!=""
  do set ticket {status=resolved,resolution=trim(resolution),resolved_by=actor,resolved_at=now}

Maintenance · App preview

Maintenance
MT-042 · Sam · 6 MarOpen

Air conditioning is not cooling

Jordan · Work note

Supply air is warm. Checking cooling controls.

Illustrative application interface · sample records.

Read the application outcomes

Floor 2 → Air conditioning not cooling → Resolved

  • Sam follows Sam’s reports

    Record a location and issue, then see the report’s status in the personal list.

  • The technician follows the full queue

    See every reported issue and resolve open tickets through the same workflow.

  • Resolution preserves the report

    Employees cannot resolve tickets; repeat resolution is refused. The browser example mirrors the rules with local page state and a reset control.

Read the factory handbook
Where this walkthrough comes from

The factory sequence and interface names follow the product documents and source code. Application behavior follows the matching complete examples on the CanLang page.

The next useful change

When your process changes, change the software.

The equipment workflow is useful. Now the company asks for Finance approval above €1,000 before delivery. Agree the rule, develop a reviewed change, and check both the new path and what must remain protected.

View CanLangBack to app
EquipmentRequestsFinance.canRule-change excerpt

Independent Finance approval above €1,000

When
 crud Equipment by=coordinator fields=name,category,active delete=none
 crud Request by=members fields=equipment,reason,amount when=row.requested_by==actor and row.status==requested delete=none
 # Review another teammate's request against the equipment catalogue.
 scenario approve(request:Request) by=reviewer
  require request.status==requested and request.requested_by!=actor
  require request.equipment.active
  do
   if request.policy==finance_threshold and request.amount!=null and request.amount.minor>100000
    set request {status=awaiting_finance,approved_by=actor,approved_at=now}
   else
    set request {status=approved,approved_by=actor,approved_at=now}
  examples request=pending
   as,request.amount,request.policy -> request.status
   first_reviewer,money(450,"EUR"),finance_threshold -> approved
   first_reviewer,money(1000,"EUR"),finance_threshold -> approved
   first_reviewer,money(1400,"EUR"),finance_threshold -> awaiting_finance
   first_reviewer,money(1400,"EUR"),original -> approved
   first_reviewer,null,original -> approved
   members,money(450,"EUR"),finance_threshold -> error(forbidden)
  examples request=pending
   as,request.requested_by,request.status -> request.status
   first_reviewer,first_reviewer,requested -> error(rule_failed)
   first_reviewer,claimant,approved -> error(rule_failed)
 # Finance must be a third person, even when one person has multiple roles.
 scenario approve_finance(request:Request) by=finance
  require request.status==awaiting_finance and request.policy==finance_threshold
  require request.requested_by!=actor and request.approved_by!=actor
  do set request {status=approved,finance_by=actor,finance_at=now}
  examples request=pending
   as,request.status,request.amount,request.approved_by -> request.status,request.finance_by
   finance_reviewer,awaiting_finance,money(1400,"EUR"),first_reviewer -> approved,finance_reviewer
   first_reviewer,awaiting_finance,money(1400,"EUR"),first_reviewer -> error(rule_failed)
   claimant,awaiting_finance,money(1400,"EUR"),first_reviewer -> error(rule_failed)
   finance_reviewer,approved,money(1400,"EUR"),first_reviewer -> error(rule_failed)
 # Record the physical asset when approved equipment reaches the requester.
 scenario deliver(request:Request,asset_tag:text) by=coordinator
  require request.status==approved and trim(asset_tag)!=""
  do set request {status=delivered,asset_tag=trim(asset_tag),delivered_at=now}
  examples request=pending
   as,request.status,asset_tag -> request.status,request.asset_tag
   coordinator,approved,"DESK-104" -> delivered,"DESK-104"
   coordinator,awaiting_finance,"DESK-104" -> error(rule_failed)
   coordinator,approved," " -> error(rule_failed)
   members,approved,"DESK-104" -> error(forbidden)
   coordinator,delivered,"DESK-104" -> error(rule_failed)
Illustrative CanLang rule-change excerpt · open the complete revised source for records, permissions and interfaces.Read the complete source

Equipment · After a rule change

Equipment
WorkspaceRequests Internal app
Equipment register

Finance review

1 awaiting Finance
EQ-1048 · Catalogue

Standing desk

Avery Active item

Approval policy
Finance review above €1,000
Alex approved · 14 Oct, 10:24€1,400 · amount locked after review
Awaiting FinanceMorgan · Finance

Decision not yet recorded. Morgan is different from Avery and Alex.

Delivery blockedFinance approval required before handover.
Review history & delivery requirements
  1. Avery requested a standing desk14 Oct, 09:05 · equipment and business reason recorded
  2. Alex approved €1,40014 Oct, 10:24 · approved details protected
  3. Finance review pendingNo Finance decision or delivery recorded. A nonempty asset tag is required after approval.
Policy applied to this request
€1,000 or less
Independent reviewer approval, then delivery.
Above €1,000
Reviewer approval, then a third person in Finance, then delivery.
Earlier requests
Earlier requests retain their original policy, including while pending. Their records and decisions remain unchanged.

Requester, reviewer and Finance approver must be different people. A recorded decision cannot be repeated.

Illustrative application interface · sample records.

Explore the approval paths and protected requests
Illustrative company policy · new requests

One amount. Two approval paths.

EmployeeRequest equipmentPositive total in EUR
Ordinary reviewerApprove another person's requestReviewed amount is now locked
€450 or exactly €1,000€1,000 or less
Ordinary approval is enough
For example, €1,400Above €1,000
Awaiting FinanceA third person approves

Delivery refused until Finance approves.

Operations records deliveryRequired approvals + nonempty asset tag

Earlier requests keep their original route. Pending and completed requests retain their previous workflow, records and decisions. Each request shows which policy applies.

Requester, initial approver and Finance approver must be three different people—even when one person holds multiple roles. Repeated decisions are refused.

Initial rule
A separate reviewer approves the request before Operations records delivery.
New rule
For new requests above €1,000, ordinary approval leads to Awaiting Finance. A separate Finance approval is required before delivery. Exactly €1,000 follows the ordinary path.
What stays protected
The requester, initial approver and Finance approver are different people. Reviewed amounts and decisions stay fixed. Earlier requests, including pending ones, keep their original workflow and records.

A lasting development home

The persistent Project keeps tools, shared files, accounts and development services ready for the next request. Forgejo retains source and software history; application records have their own storage and operating responsibilities.

Visibility, intervention and review

Spaces shows progress, blockers and live activity beside Forgejo collaboration. People can address questions or intervene with familiar tools. Current checks, review evidence and repository policy govern integration.

Illustrative company policy, applied to new requests. Earlier requests, including pending ones, keep their original workflow.

Follow the complete equipment change →

CanLang · A standalone product

Business behavior, expressed in CanLang.

CanLang is an implicit behavior language built to cover 80% of standard business use cases. Express your records, permissions and workflow rules; shared defaults supply the familiar behavior. Use it independently or alongside Soda OS.

Soda OS coordinates development. CanLang provides foundations for business applications. Its 80% business-use-case scope is a product design scope. Use CanLang independently or choose other application code within Soda OS.

Explore CanLang
View CanLangBack to app
EquipmentRequests.canExcerpt

Approval and recorded delivery

When
 crud Equipment by=coordinator fields=name,category,active delete=none
 crud Request by=members fields=equipment,reason when=row.requested_by==actor and row.status==requested delete=none
 # Review another teammate's request against the equipment catalogue.
 scenario approve(request:Request) by=reviewer
  require request.status==requested and request.requested_by!=actor
  require request.equipment.active
  do set request {status=approved,approved_by=actor,approved_at=now}
 # Record the physical asset when approved equipment reaches the requester.
 scenario deliver(request:Request,asset_tag:text) by=coordinator
  require request.status==approved and trim(asset_tag)!=""
  do set request {status=delivered,asset_tag=trim(asset_tag),delivered_at=now}

Equipment · App preview

Equipment
EQ-1042 · Avery

Standing desk

Approved
Alex approved14 Oct · details locked
Asset tag · 15 OctDESK-001
Delivered

Illustrative application interface · sample records.

How the application foundations connect
Illustrative equipment application · Shared foundations
RequestTyped record
Item
Standing desk
Requested by
Avery
Status
Requested
Team memberReads their own requests
ReviewerReads requests for review
Explicit workflow ruleApprove another person’s requestApproved
Connected interface
Request formRequest list
Forms and lists use the same records and rules.

Typed data + validation · People + access · Operations · Interfaces

A factory on infrastructure you control

Run the factory on infrastructure you control.

Install your company’s factory on a compatible x86_64 server, workstation or gaming PC. The same ISO also boots an x86_64 virtual machine on a compatible host.

Company operating model

Your team’s request. A factory to carry it forward.Equipment requests · one company workflow
OperationsWorkflow owner
The department brief

Equipment requests

“Request equipment, approve it separately, and record delivery.”

  • Separate requester and approver
  • Keep the delivery asset tag
Requirements + acceptance
equipment-requestsPersistent Project
Shared development home
SodaCoordinates
Issue #42Candidate ready

Record equipment handover

Require a delivery asset tag.

Authorised coding agent
ForgejoReviews + policy
Pull request #24Review requested

Add the delivery record

Review and checks apply to the same revision.

Required checks
Passed
Independent review
Requested
Merge
Waiting for policy
A lasting Project. Developers work over SSH in their own checkouts.
The team tries the result, accepts it and requests the next change.
Your operatorMaintains the shared foundation
  • Infrastructure
  • Accounts + access
  • Execution policy
  • Updates + recovery

Illustrative records. Departments own acceptance; deployment is separate from merge.

Departments define success. IT operates the foundation.

Departments own business requirements and acceptance. Platform administrators manage private-network infrastructure, access, accounts, execution policies, updates and recovery.

Soda coordinates. Developers can intervene.

Soda coordinates authorised work; Forgejo owns repositories, native collaboration and integration policy. Developers keep their computers, editors and terminals and can work over SSH in separate human checkouts.

Illustrative hardware

Direct install · Linux VM

Direct install · Linux VM

Gaming PC or workstation

Use the installer ISO on a compatible x86_64 PC or in an x86_64 virtual machine on a compatible host. WSL2 support for x86-64 Windows gaming PCs is planned for a future release.

Illustrative hardware

A computer of its own

A computer of its own

Dedicated hardware

Give a department’s factory a compatible x86_64 computer of its own, such as a mini PC. Keep its Projects available for continuing agent work and hands-on development.

Illustrative hardware

Virtual machine · Existing host

Virtual machine · Existing host

A compatible VM host

Boot the same installer ISO in an x86_64 virtual machine on a compatible host your team already controls.

Your company’s software factory

Start with one useful workflow.

Choose a process your team knows, define what a useful result looks like, and give it a place to keep improving.