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
Results
price = $100$100.00
quantity = 1212
total = price * quantity$1,200.00

Units and Conversions #

distance = 42.195 km
distance in miles
weight = 5 kg in pounds
Results
distance = 42.195 km42.2 km
distance in miles26.2 miles
weight = 5 kg in pounds11 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
Results
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
Results
deadline = Jan 15 2025Wednesday, January 15, 2025
remaining = deadline - today423 days
launch = today + 90 daysFriday, June 12, 2026
2 weeks from todaySaturday, March 28, 2026

Rates #

speed = 100 MB/s
cost = $50/hour
throughput = 1000 req/s
Results
speed = 100 MB/s100 MB/s
cost = $50/hour50 $/h
throughput = 1000 req/s1K req/s

Rate accumulation with over:

monthly_cost = $50/hour over 30 days
data = 100 MB/s over 1 day
Results
monthly_cost = $50/hour over 30 days$36K
data = 100 MB/s over 1 day8.24 TB

Capacity Planning #

servers = 50000 req/s at 2000 req/s per server with 25% buffer
Results
servers = 50000 req/s at 2000 req/s per server with 25% buffer32 server

Napkin Math #

Round to 2 significant figures with magnitude suffix:

1234567 as napkin
Results
1234567 as napkin1.2M

Result: ~1.2M

Multiplier Suffixes #

10K              -> 10,000
5M               -> 5,000,000
2B               -> 2,000,000,000
1.5T             -> 1,500,000,000,000

Functions #

Prefer the natural language (NL) form where available:

FunctionNL FormExample
compound(p, r, t)compound P by R over Tcompound $10000 by 7% over 30 years
depreciate(v, r, t)depreciate V by R over Tdepreciate $50000 by 15% over 5 years
grow(start, step, n)grow S by X over Ngrow $500 by $100 over 36
accumulate(r, t)rate over duration1000 req/s over 1 day
capacity(d, c, u, b)demand at cap per unit50000 req/s at 2000 req/s per server with 25% buffer
convert_rate(r, t)rate per time1200 req/s per minute
read(size, type)read X from Yread 100 MB from ssd
compress(size, algo)compress X using Ycompress 1 GB using gzip
transfer_time(s, scope, net)transfer X across Y Ztransfer 500 KB across regional gigabit
avg(a, b, c)average of a, b, caverage of $100, $200, $300
sum(a, b, c)sum of a, b, csum of $50, $75, $100
sqrt(x)square root of xsquare 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
Results
monthly_users = 2500 customers2.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, where servers is 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.headcount
Error
line 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.
Results
total = $1500$1,500.00
servers = 50000 req/s at 2000 req/s per server with 25% buffer32 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 #

FieldAlways presentDescription
sourceyesThe original CalcMark expression
valueyesDisplay-formatted result (locale-aware)
typeyesCalcMark type: number, currency, quantity, duration, rate, date, boolean
numeric_valueyesMachine-readable number (always uses . decimal, no formatting)
variablewhen assignedVariable name if this was an assignment (x = ...)
unitwhen typedUnit identifier: USD, km, second, etc.
is_explicitwhen convertedtrue if the result used an explicit in/as conversion
is_approximatewhen napkintrue if as napkin rounding was applied
date_valuefor datesISO 8601 date string (2025-01-08)

Use type for dispatch, numeric_value + unit for computation, and value for display.

Output Formats #

FlagUse case
--format jsonStructured data for programs and agents
--format textHuman-readable plain text
cm convert --to=htmlHTML document with rendered markdown and results
cm convert --to=mdMarkdown 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'
Results
x = 1010

Use distinct names for each step of a calculation:

base_cost = $100
adjusted_cost = base_cost + 15%
Results
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
Results
larks = 3 mascots3 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!)
Results
customers = 343 customers343 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 ofUse
total / num_serversdemand at cap per unit (capacity)
principal * (1 + rate) ^ yearscompound 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:

  1. Write the .cm file with calculations and prose
  2. Evaluate: cm eval analysis.cm --format json
  3. Both the source file and JSON results serve as artifacts

Document Deliverable #

Create a CalcMark document and convert it for the user:

  1. Write the .cm file with frontmatter, headers, calculations, and {{template}} interpolation
  2. Convert: cm convert report.cm --to=html -o report.html
  3. Deliver the HTML (or markdown) to the user

Iterative Analysis #

Build up a .cm file across multiple steps:

  1. Start with initial assumptions and calculations
  2. Evaluate and review results
  3. Adjust variables based on findings
  4. Re-evaluate to see updated results
  5. Repeat until the analysis is complete

Security #

  • Always ask the user before installing cm
  • Write .cm files only in the project directory or temp directory
  • Never modify shell profiles or global PATH
  • Never run cm with 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:

PathWhat’s there
spec/Language specification (grammar, types, parser)
spec/features/registry.goCanonical feature list with all functions, units, and aliases
spec/units/canonical.goAll supported physical units
impl/interpreter/Evaluation engine
testdata/Golden tests and example .cm files
testdata/examples/Complete worked examples (runnable)