Agent & API Integration
Use CalcMark as a calculation engine from scripts, AI agents, and pipelines.
CalcMark works as a command-line calculation engine. Pipe expressions in, get structured JSON out. No server, no SDK – just stdin/stdout.
Installation #
Check if cm is available:
cm version
If not found, install it:
macOS / Linux (Homebrew):
brew install calcmark/tap/calcmark
Linux (direct download):
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ARCH="amd64" ;;
aarch64) ARCH="arm64" ;;
armv6l) ARCH="armv6" ;;
esac
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
curl -sL "https://github.com/CalcMark/go-calcmark/releases/latest/download/calcmark_${OS}_${ARCH}.tar.gz" | tar xz -C /usr/local/bin cm
Always ask the user before installing software.
Quick Start #
echo "price = $100\ntax = price * 0.08\ntotal = price + tax" | cm --format json
Every result includes the display value, numeric value, type, and unit – everything a program needs to use the result downstream.
Input #
Send CalcMark expressions to stdin. Use \n to separate lines:
echo "a = 1 + 1\nb = a * 2" | cm --format json
For longer documents, use a heredoc:
cm --format json <<'EOF'
distance = 42.195 km
time = 3.5 hours
pace = time / distance
EOF
Or evaluate a file:
cm eval budget.cm --format json
Essential Syntax #
Variables and Expressions #
price = $100
quantity = 12
total = price * quantity| price = $100 | → | $100.00 |
| quantity = 12 | → | 12 |
| total = price * quantity | → | $1,200.00 |
Units and Conversions #
distance = 42.195 km
distance in miles
weight = 5 kg in pounds| distance = 42.195 km | → | 42.2 km |
| distance in miles | → | 26.2 miles |
| weight = 5 kg in pounds | → | 11 pounds |
Use front-matter to bulk covert all, or some, types of units:
---
convert_to:
system: si # or imperial
unit_categories: [Custom, Mass, Volume] # won't convert Temperatures, Length, etc.
---Currency #
Supported symbols: $ (USD), € (EUR), £ (GBP), ¥ (JPY). Any 3-letter ISO code works as a postfix: 100 CHF, 50 CAD.
Percentages #
marked_up = $100 + 15%
discounted = $250 - 20%
15% of $2000| marked_up = $100 + 15% | → | $115.00 |
| discounted = $250 - 20% | → | $200.00 |
| 15% of $2000 | → | $300.00 |
When added/subtracted with another type, percentages widen: $100 + 15% = $115.00.
Dates and Durations #
deadline = Jan 15 2025
remaining = deadline - today
launch = today + 90 days
2 weeks from today| deadline = Jan 15 2025 | → | Wednesday, January 15, 2025 |
| remaining = deadline - today | → | 423 days |
| launch = today + 90 days | → | Friday, June 12, 2026 |
| 2 weeks from today | → | Saturday, March 28, 2026 |
Rates #
speed = 100 MB/s
cost = $50/hour
throughput = 1000 req/s| speed = 100 MB/s | → | 100 MB/s |
| cost = $50/hour | → | 50 $/h |
| throughput = 1000 req/s | → | 1K req/s |
Rate accumulation with over:
monthly_cost = $50/hour over 30 days
data = 100 MB/s over 1 day| monthly_cost = $50/hour over 30 days | → | $36K |
| data = 100 MB/s over 1 day | → | 8.24 TB |
Capacity Planning #
servers = 50000 req/s at 2000 req/s per server with 25% buffer| servers = 50000 req/s at 2000 req/s per server with 25% buffer | → | 32 server |
Napkin Math #
Round to 2 significant figures with magnitude suffix:
1234567 as napkin| 1234567 as napkin | → | 1.2M |
Result: ~1.2M
Multiplier Suffixes #
10K -> 10,000
5M -> 5,000,000
2B -> 2,000,000,000
1.5T -> 1,500,000,000,000Functions #
Prefer the natural language (NL) form where available:
| Function | NL Form | Example |
|---|---|---|
compound(p, r, t) | compound P by R over T | compound $10000 by 7% over 30 years |
depreciate(v, r, t) | depreciate V by R over T | depreciate $50000 by 15% over 5 years |
grow(start, step, n) | grow S by X over N | grow $500 by $100 over 36 |
accumulate(r, t) | rate over duration | 1000 req/s over 1 day |
capacity(d, c, u, b) | demand at cap per unit | 50000 req/s at 2000 req/s per server with 25% buffer |
convert_rate(r, t) | rate per time | 1200 req/s per minute |
read(size, type) | read X from Y | read 100 MB from ssd |
compress(size, algo) | compress X using Y | compress 1 GB using gzip |
transfer_time(s, scope, net) | transfer X across Y Z | transfer 500 KB across regional gigabit |
avg(a, b, c) | average of a, b, c | average of $100, $200, $300 |
sum(a, b, c) | sum of a, b, c | sum of $50, $75, $100 |
sqrt(x) | square root of x | square root of 144 |
number(x) | number($100) → 100 (strips unit) |
Run cm help functions for the complete list with signatures.
Smart Type Handling #
CalcMark automatically handles many type combinations without number():
monthly_users = 2500 customers
price = $49
revenue = price * monthly_users| monthly_users = 2500 customers | → | 2.5K customers |
| price = $49 | → | $49.00 |
| revenue = price * monthly_users | → | $122.5K |
Result: $122,500.00 – currency * quantity gives currency, dropping the custom unit.
More examples:
$100 + 15%→$115.00(percentage widening)€4500 in USD→ converts using frontmatter exchange rates$450 * servers→ currency, whereserversis a quantity from capacity planning
Use number() only when you need a dimensionless value, such as dividing two currencies for a ratio: number(ltv) / number(cac).
Frontmatter #
Documents can start with YAML frontmatter for configuration:
---
title: Budget Analysis
locale: en-US
globals:
tax_rate: 0.32
headcount: 12
exchange:
USD_EUR: 0.92
EUR_USD: 1.09
---
Reference globals with @globals.name:
---
globals:
headcount: 15
---
team_cost = salary * @globals.headcountline 5: undefined_variable: undefined variable "salary"An agent can research current exchange rates and insert them into frontmatter for accurate multi-currency documents.
Run cm help frontmatter for all directives including scale and convert_to.
Scaling is handy for things like scaling recipes:
---
scale:
factor: 2 # double a recipe
unit_categories: [Volume, Mass] # don't double the oven temperature!
---Template Interpolation #
Embed calculated values in prose with {{variable_name}}:
total = $1500
servers = 50000 req/s at 2000 req/s per server with 25% buffer
The project costs {{total}} and requires {{servers}} app servers.| total = $1500 | → | $1,500.00 |
| servers = 50000 req/s at 2000 req/s per server with 25% buffer | → | 32 server |
When combined with cm convert --to=html, this produces readable reports with inline results.
JSON Response Structure #
The response is an array of blocks. Each block is either "calculation" or "text" (markdown):
{
"blocks": [
{
"type": "text",
"source": ["# Budget"],
"html": "<h1 id=\"budget\">Budget</h1>\n"
},
{
"type": "calculation",
"source": ["price = $100", "tax = price * 0.08"],
"results": [
{
"source": "price = $100",
"value": "$100.00",
"type": "currency",
"numeric_value": 100,
"unit": "USD",
"variable": "price"
},
{
"source": "tax = price * 0.08",
"value": "$8.00",
"type": "currency",
"numeric_value": 8,
"unit": "USD",
"variable": "tax"
}
]
}
]
}
Result Fields #
| Field | Always present | Description |
|---|---|---|
source | yes | The original CalcMark expression |
value | yes | Display-formatted result (locale-aware) |
type | yes | CalcMark type: number, currency, quantity, duration, rate, date, boolean |
numeric_value | yes | Machine-readable number (always uses . decimal, no formatting) |
variable | when assigned | Variable name if this was an assignment (x = ...) |
unit | when typed | Unit identifier: USD, km, second, etc. |
is_explicit | when converted | true if the result used an explicit in/as conversion |
is_approximate | when napkin | true if as napkin rounding was applied |
date_value | for dates | ISO 8601 date string (2025-01-08) |
Use type for dispatch, numeric_value + unit for computation, and value for display.
Output Formats #
| Flag | Use case |
|---|---|
--format json | Structured data for programs and agents |
--format text | Human-readable plain text |
cm convert --to=html | HTML document with rendered markdown and results |
cm convert --to=md | Markdown with results inline |
Convert to a file with -o:
cm convert report.cm --to=html -o report.html
Error Handling #
Undefined variables and type errors produce a non-zero exit code and an error message on stderr:
echo "x = unknown + 1" | cm --format json
# Exit code 1
# stderr: evaluation error: undefined_variable: undefined variable "unknown"
Errors go to stderr as plain text, not JSON. Always check the exit code.
Silent misinterpretation: If CalcMark doesn’t recognize an expression, it treats it as markdown prose. The JSON will contain "type": "text" blocks instead of "type": "calculation". Always verify your output contains calculation blocks when you expect them.
Common Pitfalls #
Variables Are Immutable #
Variables cannot be reassigned. This will error:
x = 10
x = 20 # ERROR: variable_redefinition: cannot reassign 'x'| x = 10 | → | 10 |
Use distinct names for each step of a calculation:
base_cost = $100
adjusted_cost = base_cost + 15%| base_cost = $100 | → | $100.00 |
| adjusted_cost = base_cost + 15% | → | $115.00 |
Calculations Are Separate From Markdown #
Calculations live on their own lines, not interspersed with markdown. The only exception is {{ interpolated_variables}}.
OK:
Hello there. We need {{ larks }}.
larks = 3 mascots| larks = 3 mascots | → | 3 mascots |
NOT OK:
Hello there. We need `larks = 3 mascots` or `{{ 3 mascots }}` or anything similar.Unit Propagation #
Arithmetic on quantities preserves the unit of the numerator. This can produce unexpected results:
customers = 343 customers
servers_raw = customers / 10 # Result: 34.3 customers (NOT servers!)| customers = 343 customers | → | 343 customers |
Use the NL capacity form to get correct unit conversion:
servers = 343 customers at 10 customers per server # Result: 35 server ✓Prefer NL Forms Over Raw Arithmetic #
CalcMark’s natural language functions handle rounding, units, and edge cases that raw division does not. When a built-in function exists, use it:
| Instead of | Use |
|---|---|
total / num_servers | demand at cap per unit (capacity) |
principal * (1 + rate) ^ years | compound P by R over T |
start + (step * periods) | grow S by X over N |
Run cm help functions to discover all available NL forms.
Error Output Goes to stderr #
Errors are plain text on stderr, not JSON. If you pipe cm output directly into a JSON parser and an error occurs, the parser will receive empty input and fail silently. Always check the exit code:
if ! result=$(cm eval file.cm --format json 2>/dev/null); then
cm eval file.cm 2>&1 # re-run to see the error message
fi
Verbose Mode #
By default, only the last result is shown in text mode. Use -v to get all intermediate values:
echo "a = 10\nb = a * 2\nc = b + 1" | cm -v
# 10
# 20
# 21
In JSON mode (--format json), all results are always included regardless of -v.
Feature Discovery #
List all available functions, units, and frontmatter directives at runtime:
cm help functions # All functions with signatures and NL forms
cm help constants # All unit constants with aliases
cm help frontmatter # All frontmatter directives with valid options
cm help --all # Everything at once
Workflow Patterns #
Quick Calculation #
Pipe a one-liner and extract the result from JSON:
echo "servers = 50000 req/s at 2000 req/s per server with 25% buffer" | cm --format json
Research Artifact #
Write a .cm file as evidence of analytical work:
- Write the
.cmfile with calculations and prose - Evaluate:
cm eval analysis.cm --format json - Both the source file and JSON results serve as artifacts
Document Deliverable #
Create a CalcMark document and convert it for the user:
- Write the
.cmfile with frontmatter, headers, calculations, and{{template}}interpolation - Convert:
cm convert report.cm --to=html -o report.html - Deliver the HTML (or markdown) to the user
Iterative Analysis #
Build up a .cm file across multiple steps:
- Start with initial assumptions and calculations
- Evaluate and review results
- Adjust variables based on findings
- Re-evaluate to see updated results
- Repeat until the analysis is complete
Security #
- Always ask the user before installing
cm - Write
.cmfiles only in the project directory or temp directory - Never modify shell profiles or global PATH
- Never run
cmwith elevated privileges
Agent Skill #
If you use an AI coding agent, you can teach it CalcMark with a one-line install. The CalcMark Agent Skill gives your agent an offline cheat sheet covering syntax, CLI patterns, and JSON output format — so it can write .cm files, run calculations, and convert documents without consulting external docs.
Supported platforms: Claude Code, Cursor, GitHub Copilot CLI, and Gemini CLI.
Each platform installs with a single curl command. See the agent-skill README for instructions.
Source Code #
CalcMark is open source: github.com/CalcMark/go-calcmark
Key directories for understanding the language:
| Path | What’s there |
|---|---|
spec/ | Language specification (grammar, types, parser) |
spec/features/registry.go | Canonical feature list with all functions, units, and aliases |
spec/units/canonical.go | All supported physical units |
impl/interpreter/ | Evaluation engine |
testdata/ | Golden tests and example .cm files |
testdata/examples/ | Complete worked examples (runnable) |