i2y/ritsu/dandori

Claude Code and agent skill by i2y/ritsu

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Write, check and build dandori workflows (`.flow` files), typed workflows that call APIs, rules, agents, decision models (TypeSafe's Jev, a server of its System One API such as Ollama, OpenAI's Decisions API), koyomi's dates, chobo's books and code of your own, checked before they run and built for Temporal (TypeScript, Python or Go), AWS Step Functions, AWS Lambda durable functions, Argo Workflows and pydantic-graph. Use when a workflow (take a payment now and capture it later, reserve and ship an order, route an inquiry, wait for a person's approval) has to be written or changed as a `.flow`; when a dandori diagnostic (E001-E050, W030, W032, W101-W104) has to be fixed; when a workflow has to be shown to the person who reviews it, drawn; or when a `.flow` has to be built for a platform and its generated code wired up.

Install

npx vskill@latest install i2y/ritsu/dandori

SKILL.md

When this applies

The job is a workflow: steps that call other systems, wait, retry, and move something in another system from state to state. A payment authorized when a stay is booked and captured at check-out; the lines of an order reserved side by side, packed and shipped; an inquiry read, routed and answered; an application scored and, when the score says so, approved by a person. dandori writes it once as a .flow, checks it before it runs, and builds it for the platform the team runs.

It does not apply to the decisions themselves when they are tables: a fee schedule, an eligibility test, a routing policy. Those are rulec rules, which a .flow calls (rulec has a skill of its own). Nor does it apply to computing things: a .flow has no comparison and no arithmetic, so whatever compares or computes is a rule or a task.

The files bundled with this skill are listed in §7. Read them when you need them, not all up front.


Working with dandori

Your part is to write the .flow, get it past ritsu dandori check, and build it. Two things stay with people:

  • what the other systems guarantee: whether a call can be repeated safely, which errors it

returns, which events happen on their side by themselves. That comes from their documentation or their owners, and §3 says when to ask.

  • the platform and the code around the workflow: which platform runs it, the credentials, and

the code of the tasks that are yours to write.

Run every command here as ritsu dandori <command> (through a link to ritsu named dandori, dandori <command> is the same). It reads the rules, dates files and books a workflow uses in the same process; dandori built alone from its crate reads none of them and says so (E018). Everything is reachable from the command line: ritsu dandori --help lists the commands, and ritsu dandori check --format json gives the diagnostics as data (§5). There is no step where you have to read dandori's source. In a project with rules, dates or books, ritsu check checks the .flow files with them and across them: whether a call keeps a rule's preconditions, a date's days, a transfer's amounts, refusals and holds (the ritsu skill has the codes).

1. The loop

  1. Find the workflow. List what it calls, what it waits for, what it returns, and the things

in other systems whose state it moves (a PaymentIntent, an order). Settle the platform (§6); Temporal is the main one.

  1. Write the `.flow` (§2): the types, the tasks and the cases first, then the flow.
  2. Check it: ritsu dandori check <file.flow>. Every diagnostic comes with the run that gets there;

fix it (§4; ritsu dandori explain <CODE> explains one code) and check again, until it prints <file.flow>: ok. A warning does not stop a build, but it says something true about the workflow.

  1. Watch it run: ritsu dandori scenarios <file.flow> --out <dir> writes scenarios (001.json,

002.json, …) that together take every arm, every handler of an error, and every way a case can move; for each place of the inputs held to a range, one more has an input just outside it there, which every platform turns away at once (Dandori.BadInput). ritsu dandori run <file.flow> --scenario <dir>/001.json plays one in the reference interpreter and prints each call with its answer, and how the run ended.

  1. Show it to a person: ritsu dandori doc <file.flow> > <file>.md draws the flow as Mermaid

charts, with a table of every call (what it calls, its retries, where each of its errors goes) and of every way the workflow can end, with the state each case is left in, and the rules it calls as ritsu rulec doc renders them, each a page for people. Put it in the pull request, where GitHub draws the charts, for the person who reviews the workflow. --format html writes one page on which each scenario lights up the way its run goes, and each rule's page opens with a case to try on it. diagrams.md says what is on the picture.

  1. Build it: ritsu dandori gen <file.flow> --target temporal-typescript writes the code into

generated/temporal-typescript/ (--out for another directory); give --target once for each platform wanted, and each goes into its own <dir>/<target>/. gen stops, and writes nothing, when a platform cannot do what the workflow asks (E050), a run can outgrow it (E040), or its code cannot keep a name (E051). The same line with --check in CI writes nothing and exits 1 if a file is missing or differs.

  1. Wire it up: write the tasks that are yours (the OwnTasks the generated code asks for), give

the Transport (io.ts, io.py) its credentials, and start the generated worker, or deploy what the target wrote. When the workflow calls rules, ritsu rulec gen <rule> --target <the wrappers' language> --out rulec writes the code the generated wrappers import (typescript, python or go; ritsu gen writes a whole project as one package instead). A precondition of a rule that ritsu check could not decide (its W201) is checked by the built workflow when it runs, and a run that breaks it fails with Dandori.BrokenPrecondition. platforms.md says what each target writes.

2. The language on one page

A whole workflow: the review example. Jev scores an application and says how sure it is, a rulec rule weighs the verdict and how sure it is, and a person approves what the rule sends on, until 17:00 on the third business day, a time koyomi's dates file gives.

flow
workflow review v1
description "Jev scores an application and says how sure it is, and a rule decides whether the verdict is acted on at once or goes to a person for approval, due by 17:00 on the third business day after it comes in: approving at once asks more certainty than rejecting at once. Written for Temporal: the scoring is an activity dandori writes, which calls Jev with TypeSafe's key (TYPESAFE_API_KEY) on the workers of its own task queue, which may be written in another language, and so does the notice, an activity you write; the rule and the date of the approval run in the worker of the workflow; the approver's tool answers the callback by the update the generated client sends"
use rule policy from "../rules/review_policy.rule"
use dates approvals from "../dates/approval_terms.cal"
record Application
id : string
amount : int
purpose : string
record Score
verdict : policy.verdict
sure : rate[step 1%] range >=0 <=100
record Approval
approver : string
inputs
application : Application
outputs
verdict : policy.verdict
# Jev places what the applicant wrote on the scale of verdicts, from the lowest level, and how
# sure it is of the verdict comes as a rate, for the rule to weigh.
task score(purpose: string) -> Score
jev
verdict score "How clearly is the money for running the business?"
reject "It is for something personal or speculative, or against the law"
hold "It is for the business, but the statement leaves unclear what it pays for"
approve "It pays for a named part of running the business, such as stock, equipment, staff or premises"
sure confidence of verdict
model "jev-1.13.0"
queue "scoring"
errors busy = 429, overloaded = 529
retry 2 times every 10 seconds on busy, overloaded
timeout 10 seconds
# Someone approves in a tool of their own, and the answer comes back with the callback's id. The
# approver is told when the approval is due, and the wait ends then.
task ask_for_approval(application_id: string, amount: int, sure: rate[step 1%], by: timestamp) -> Approval
callback
timeout until by
task notify(application_id: string, text: string)
queue "notify"
idempotent
flow
let r = score(purpose: application.purpose)
on failure => fail Unscorable "Could not score application {application.id}"
let d = policy(verdict: r.verdict, sure: r.sure)
match d.decision
approve, reject => pass
ask =>
let due = approvals.due(received: now)
let a = ask_for_approval(application_id: application.id, amount: application.amount, sure: r.sure, by: due.at)
on timeout => fail NoAnswer "No approval by 17:00 on the third business day"
notify(application_id: application.id, text: "{a.approver} approved application {application.id}")
succeed verdict = approve
notify(application_id: application.id, text: "Application {application.id} was reviewed: {r.verdict}")
succeed verdict = r.verdict

Indentation makes the blocks. # starts a comment.

Declarations
text
workflow <name> v<N> [implements <api>.<Service>]
the name and version (on Temporal, both are in the
workflow type and the task queue: review_v1); with
implements, the workflow is the service of a .proto
read by use proto (services.md)
description "<text>"
kind standard | express Step Functions; an Express workflow has limits (E031)
use rule <name> from "<file.rule>" a rulec rule, read by rulec; under it,
lambda "<function>" (Step Functions, durable functions)
or connect "<url>" (the rule's Connect service, which
every platform calls; Step Functions also needs
connection "<EventBridge connection>"),
and local (a local activity on Temporal). A rule that
walks a list cannot be used (E005), nor one with an
input or an output that may be none (T?). An enums
file has no outputs: its enums are types
(<name>.<enum>), and a call of it is E005
use openapi|smithy|proto <name> from "<file>" an API description; under it, url "<base>"
(a proto needs one to `connect` to it)
use dates <name> from "<file.cal>" a dates file of koyomi's; each date is called like a
rule, <name>.<date>(<input>: …), and answers {day, at};
under it, lambda "<function>" and local, as for a rule
use book <name> from "<file.book>" a book of chobo's, whose transfers tasks run operations
on; under it, lambda "<function>" (Step Functions)
enum <Name> = <value> | <value> | …
record <Name> then one field a line, <name> : <type>
inputs, outputs the same, for what a run takes and gives back
task <name>(<param>: <type>, …) [-> <type>]
case <name> : <Record> follows <rule>.<machine>
case <name> : <book>.<transfer> follows <book>.<transfer> a hold of a book, as a case
flow the steps
on failure runs when a task fails and nothing handled it, then the
run fails with the same error
on cancel runs when the workflow is cancelled (Temporal only)

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/i2y/ritsu/dandori/badge)](https://verified-skill.com/skills/i2y/ritsu/dandori)

Something wrong with this skill or its page? Tell us.