Files
symclaw/IMPLEMENTATION_PLAN.md
T

27 KiB
Raw Blame History

SymClaw — Implementation Plan & Critical Analysis

Project: Open-Source Symbolic Computing for the Agentic Age

Codename: SymClaw
Stack: Rust Symbolic Engine + OpenClaw Agentic Bridge
Author: Omar (HPC-AI Platform)
Date: 2026-02-12
Status: Architecture Review


1. Strategic Assessment

1.1 What Makes This a Paradigm Shift

The roadmap you've drafted is strong, but to truly be paradigm-shifting, there are dimensions the original plan underweights. Here's what elevates this from "another CAS" to a genuine platform shift:

The Killer Insight: Deterministic Compute + Agentic Intelligence

Every existing CAS is either (a) deterministic but dumb (Mathematica, SymPy — you type exact commands) or (b) intelligent but unreliable (ChatGPT doing math — hallucinates). SymClaw is the first system where:

  • The LLM handles intent ("what's the derivative of this messy physics equation?")
  • The symbolic engine guarantees correctness (deterministic Rust computation)
  • The e-graph finds the optimal form (not just an answer, but the best answer)
  • The agentic layer delivers it anywhere (WhatsApp, Telegram, Canvas, voice)

This is the "compiler + IDE" moment for scientific computing. No one else is building this.

1.2 Critical Gaps in the Original Roadmap

Gap Why It Matters Resolution
No numeric fallback strategy Many real-world problems can't be solved symbolically Add hybrid symbolic-numeric pipeline (Phase 2.5)
No error recovery / graceful degradation Users will hit unsolvable expressions constantly Implement "best effort" mode with confidence scoring
Parser underspecified Input parsing is 50% of the user experience Dedicate Sprint 1 to parser with extensive edge-case handling
No caching layer Same expressions re-evaluated across sessions Add expression-level memoization with LRU cache
Security model missing Arbitrary expression evaluation is a DoS vector Expression complexity limits, timeout enforcement, sandboxing
No migration path from existing tools Scientists won't switch without import capability SymPy/LaTeX import in V0.5, Mathematica notebook import in V1.0
Collaboration undefined Research is collaborative Multi-user Canvas sessions via OpenClaw multi-agent routing (V1.0)
No offline mode Scientists work on planes, in labs without internet WASM module works fully offline; LLM intent parsing degrades to direct command mode

1.3 Build vs. Integrate Decisions

Before writing a single line, these decisions save months:

Component Build Integrate Recommendation
Expression AST Build — core IP, must be Arc-based for your cluster
Parser Build with nom — need custom notation support
Simplifier Hybrid egg crate Integrate egg, build rule sets on top
Differentiation Build — well-defined algorithms, your rules
Integration Build core; consider SymPy FFI for edge cases
Linear Algebra nalgebra Integrate nalgebra for numeric, build symbolic layer
Plotting Plotly.js Integrate in Canvas; don't build a plotting library
LaTeX rendering KaTeX Integrate — battle-tested, fast, WASM-compatible
Arbitrary precision num crate Integrate
WASM compilation wasm-bindgen Integrate

2. Architecture Deep Dive

2.1 Expression AST — The Foundation

This is the most critical design decision. Get it wrong and everything downstream suffers.

// Core expression type — every operation in the system flows through this
#[derive(Clone, Hash, Eq, PartialEq, Debug)]
pub enum Expr {
    // Atoms
    Num(Rational),          // Exact: 3/7, -42, 0
    Float(OrderedFloat<f64>), // IEEE 754 when exact isn't needed
    Symbol(Symbol),          // Interned string: x, y, theta
    Complex(Arc<Expr>, Arc<Expr>), // a + bi
    
    // N-ary operations (flattened, canonically sorted)
    Add(Vec<Arc<Expr>>),     // a + b + c (not nested)
    Mul(Vec<Arc<Expr>>),     // a * b * c (not nested)
    
    // Binary operations
    Pow(Arc<Expr>, Arc<Expr>),  // base^exponent
    
    // Functions
    Func(FuncId, Vec<Arc<Expr>>), // sin(x), log(x, base), custom(a, b, c)
    
    // Calculus
    Derivative(Arc<Expr>, Symbol, u32),  // d^n f / dx^n
    Integral(Arc<Expr>, Symbol, Option<Bounds>), // ∫f dx or ∫_a^b f dx
    Limit(Arc<Expr>, Symbol, Arc<Expr>, Direction),
    Sum(Arc<Expr>, Symbol, Arc<Expr>, Arc<Expr>),    // Σ
    Product(Arc<Expr>, Symbol, Arc<Expr>, Arc<Expr>), // Π
    
    // Structural
    Eq(Arc<Expr>, Arc<Expr>),        // equation
    Matrix(MatrixData),               // symbolic matrix
    Piecewise(Vec<(Arc<Expr>, Condition)>),
    
    // Meta
    Undefined,  // 0/0, etc.
    Infinity(Sign),
}

Critical Design Notes:

  1. Arc, not Box — You need Send + Sync for rayon parallelism across your Pi cluster nodes. The ~8 bytes overhead per Arc is negligible vs. the threading flexibility.

  2. Interned Symbols — Use the string_interner crate. In a typical session, the same variable names (x, y, t, theta) appear thousands of times. Interning reduces memory and makes comparison O(1).

  3. Canonical OrderingAdd(vec![x, 3]) and Add(vec![3, x]) must be the same expression. Sort commutative operands by a canonical ordering (constants first, then symbols alphabetically, then complex expressions by depth). This is essential for e-graph efficiency.

  4. Flattened N-ary(a + b) + c becomes Add(vec![a, b, c]). This eliminates association ambiguity and makes pattern matching simpler.

2.2 The Egg Integration — This Is Your Moat

The equality saturation engine via egg is what differentiates SymClaw from SymPy. Here's why and how:

Why it matters:

Traditional CAS simplifiers apply rules greedily: pick a rule, apply it, repeat. This gets stuck in local optima. Example:

Input: (x^2 - 1) / (x - 1)
Greedy: tries to simplify numerator and denominator separately → stuck
Egg:    discovers x^2 - 1 = (x+1)(x-1), cancels → (x+1) ✓

Egg explores ALL possible rewrites simultaneously using e-graphs, then extracts the simplest result. This is provably optimal (given enough rules and iterations).

Implementation strategy:

use egg::{*, rewrite as rw};

define_language! {
    pub enum MathLang {
        Num(i64),
        "+" = Add([Id; 2]),
        "*" = Mul([Id; 2]),
        "/" = Div([Id; 2]),
        "^" = Pow([Id; 2]),
        "neg" = Neg([Id; 1]),
        "sin" = Sin([Id; 1]),
        "cos" = Cos([Id; 1]),
        "ln" = Ln([Id; 1]),
        "exp" = Exp([Id; 1]),
        "d" = Deriv([Id; 2]),  // d(expr, var)
        Symbol(Symbol),
    }
}

fn math_rules() -> Vec<Rewrite<MathLang, ConstantFold>> {
    vec![
        // Arithmetic identities
        rw!("add-0";       "(+ ?a 0)"     => "?a"),
        rw!("mul-1";       "(* ?a 1)"     => "?a"),
        rw!("mul-0";       "(* ?a 0)"     => "0"),
        rw!("pow-0";       "(^ ?a 0)"     => "1"),
        rw!("pow-1";       "(^ ?a 1)"     => "?a"),
        
        // Commutativity
        rw!("add-comm";    "(+ ?a ?b)"    => "(+ ?b ?a)"),
        rw!("mul-comm";    "(* ?a ?b)"    => "(* ?b ?a)"),
        
        // Associativity
        rw!("add-assoc";   "(+ ?a (+ ?b ?c))" => "(+ (+ ?a ?b) ?c)"),
        rw!("mul-assoc";   "(* ?a (* ?b ?c))" => "(* (* ?a ?b) ?c)"),
        
        // Distribution
        rw!("distribute";  "(* ?a (+ ?b ?c))" => "(+ (* ?a ?b) (* ?a ?c))"),
        rw!("factor";      "(+ (* ?a ?b) (* ?a ?c))" => "(* ?a (+ ?b ?c))"),
        
        // Differentiation rules (the magic — egg discovers derivatives)
        rw!("d-const";     "(d ?c ?x)" => "0" if is_const("?c", "?x")),
        rw!("d-var";       "(d ?x ?x)" => "1"),
        rw!("d-add";       "(d (+ ?a ?b) ?x)" => "(+ (d ?a ?x) (d ?b ?x))"),
        rw!("d-mul";       "(d (* ?a ?b) ?x)" => 
                           "(+ (* (d ?a ?x) ?b) (* ?a (d ?b ?x)))"),
        rw!("d-pow";       "(d (^ ?a ?n) ?x)" => 
                           "(* (* ?n (^ ?a (+ ?n -1))) (d ?a ?x))" 
                           if is_const("?n", "?x")),
        rw!("d-sin";       "(d (sin ?a) ?x)" => "(* (cos ?a) (d ?a ?x))"),
        rw!("d-cos";       "(d (cos ?a) ?x)" => "(* (neg (sin ?a)) (d ?a ?x))"),
        rw!("d-exp";       "(d (exp ?a) ?x)" => "(* (exp ?a) (d ?a ?x))"),
        rw!("d-ln";        "(d (ln ?a) ?x)"  => "(* (/ 1 ?a) (d ?a ?x))"),
        
        // Trig identities
        rw!("sin2+cos2";   "(+ (^ (sin ?a) 2) (^ (cos ?a) 2))" => "1"),
        rw!("exp-ln";      "(exp (ln ?a))" => "?a"),
        rw!("ln-exp";      "(ln (exp ?a))" => "?a"),
    ]
}

Explain Mode — The "Show Your Work" Feature:

// Using egg's explain API to show step-by-step derivation
let runner = Runner::default()
    .with_explanations_enabled()
    .with_expr(&start)
    .run(&rules);

let explanation = runner.explain_equivalence(&start, &goal);
// Returns: [(rule_name, before_expr, after_expr), ...]
// User sees: "Applied product rule → Applied power rule → Simplified"

This is huge for education. No other CAS can show WHY it simplified an expression.

2.3 OpenClaw Skill Architecture

┌─────────────────────────────────────────┐
│           User's Phone/Desktop           │
│  Telegram │ WhatsApp │ Canvas │ WebChat  │
└─────────────┬───────────────────────────┘
              │ message: "derive sin(x^2)"
              ▼
┌─────────────────────────────────────────┐
│         OpenClaw Gateway (Node.js)       │
│  ┌─────────────────────────────────┐    │
│  │ LLM (Claude/GPT) — Intent Parse │    │
│  │ "derive sin(x^2)"               │    │
│  │  → tool: math_eval              │    │
│  │  → expr: "d/dx(sin(x^2))"      │    │
│  └──────────────┬──────────────────┘    │
│                 │                        │
│  ┌──────────────▼──────────────────┐    │
│  │    symclaw Skill (JS wrapper)    │    │
│  │  ┌────────────────────────┐     │    │
│  │  │ Option A: WASM Module  │     │    │
│  │  │ (in-process, fast)     │     │    │
│  │  └────────────────────────┘     │    │
│  │  ┌────────────────────────┐     │    │
│  │  │ Option B: Subprocess   │     │    │
│  │  │ (native, full perf)   │     │    │
│  │  └────────────────────────┘     │    │
│  └──────────────┬──────────────────┘    │
│                 │ result + LaTeX         │
│  ┌──────────────▼──────────────────┐    │
│  │      Response Formatter          │    │
│  │  Telegram: ASCII + LaTeX image  │    │
│  │  Canvas: Interactive HTML        │    │
│  │  WhatsApp: ASCII + rendered PNG │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

2.4 Canvas Manipulate — Real-Time Math Exploration

This is the feature that makes scientists' eyes light up. Mathematica's Manipulate[] is one of its most beloved features. Here's how we replicate it:

// A2UI JSONL payload pushed to Canvas
{"surfaceUpdate": {
  "surfaceId": "manipulate-1",
  "components": [
    {"id": "title", "component": {"Text": {
      "text": {"literalString": "f(x) = a·sin(b·x + c)"},
      "usageHint": "h2"
    }}},
    {"id": "slider-a", "component": {"Slider": {
      "min": 0.1, "max": 5.0, "step": 0.1, "value": 1.0,
      "label": "a (amplitude)"
    }}},
    {"id": "slider-b", "component": {"Slider": {
      "min": 0.1, "max": 10.0, "step": 0.1, "value": 1.0,
      "label": "b (frequency)"  
    }}},
    {"id": "slider-c", "component": {"Slider": {
      "min": -3.14, "max": 3.14, "step": 0.01, "value": 0.0,
      "label": "c (phase)"
    }}},
    {"id": "plot", "component": {"WebView": {
      "html": "<canvas id='plot'></canvas><script>/* Plotly + WASM eval */</script>"
    }}}
  ]
}}

The magic: slider changes trigger WASM evaluation directly in the Canvas JavaScript, no round-trip to the server needed. 30fps updates on a phone.


3. Testing Strategy — Correctness Is Non-Negotiable

3.1 The Testing Pyramid

                    ╱╲
                     ╲     Manual Testing
                   5% ╲    (demo to researchers, get feedback)
                 ╱──────╲
                        ╲   Stress/Load Tests
                  10%    ╲  (Pi cluster, WASM limits, DoS)
              ╱────────────╲
             ╱              ╲  Integration Tests
                 15%        ╲ (OpenClaw → Engine → Canvas pipeline)
           ╱──────────────────╲
          ╱                    ╲  Property-Based Tests
                25%            ╲ (proptest: numerical invariants)
        ╱────────────────────────╲
       ╱                          ╲  Unit Tests
                45%                ╲ (every rule, every function)
     ╱──────────────────────────────╲

3.2 Property-Based Testing (The Secret Weapon)

use proptest::prelude::*;

// Strategy: generate random mathematical expressions
fn arb_expr(depth: u32) -> impl Strategy<Value = Expr> {
    let leaf = prop_oneof![
        (1..100i64).prop_map(|n| Expr::Num(Rational::from(n))),
        Just(Expr::Symbol("x".into())),
        Just(Expr::Symbol("y".into())),
    ];
    
    leaf.prop_recursive(depth, 256, 10, |inner| {
        prop_oneof![
            (inner.clone(), inner.clone()).prop_map(|(a, b)| 
                Expr::Add(vec![Arc::new(a), Arc::new(b)])),
            (inner.clone(), inner.clone()).prop_map(|(a, b)| 
                Expr::Mul(vec![Arc::new(a), Arc::new(b)])),
            inner.clone().prop_map(|a| 
                Expr::Func(FuncId::Sin, vec![Arc::new(a)])),
        ]
    })
}

proptest! {
    // INVARIANT 1: Simplification preserves numerical value
    #[test]
    fn simplify_preserves_value(
        expr in arb_expr(4),
        x in -10.0f64..10.0,
    ) {
        let original = expr.eval(&[("x", x)]);
        let simplified = simplify(&expr);
        let result = simplified.eval(&[("x", x)]);
        
        if original.is_finite() && result.is_finite() {
            prop_assert!((original - result).abs() < 1e-10,
                "Simplification changed value: {} → {}", original, result);
        }
    }
    
    // INVARIANT 2: Simplification is idempotent
    #[test]
    fn simplify_idempotent(expr in arb_expr(3)) {
        let once = simplify(&expr);
        let twice = simplify(&once);
        prop_assert_eq!(once, twice, "Not idempotent");
    }
    
    // INVARIANT 3: Parse round-trip
    #[test]
    fn parse_roundtrip(expr in arb_expr(3)) {
        let printed = format!("{}", expr);
        let reparsed = parse(&printed).unwrap();
        prop_assert_eq!(expr, reparsed, "Round-trip failed");
    }
    
    // INVARIANT 4: Derivative + Integral approximate inverse
    #[test]
    fn derivative_integral_roundtrip(
        expr in arb_polynomial(3),  // restrict to polynomials for tractability
        x in -5.0f64..5.0,
    ) {
        let d = differentiate(&expr, "x");
        let i = integrate(&d, "x");
        let diff = (expr.eval(&[("x", x)]) - i.eval(&[("x", x)])).abs();
        // Should differ by at most a constant
        let diff2 = (expr.eval(&[("x", x + 0.1)]) - i.eval(&[("x", x + 0.1)])).abs();
        prop_assert!((diff - diff2).abs() < 1e-8,
            "Integral of derivative should differ by constant");
    }
}

3.3 Integration Test: Full Pipeline

// test/integration/telegram-to-canvas.test.ts
describe('Telegram → Engine → Canvas pipeline', () => {
    it('should differentiate and render on Canvas', async () => {
        // 1. Simulate Telegram message
        const response = await gateway.handleMessage({
            channel: 'telegram',
            sender: '+15555551234',
            text: 'What is the derivative of x^3 * sin(x)?'
        });
        
        // 2. Verify text response
        expect(response.text).toContain('3x²·sin(x) + x³·cos(x)');
        
        // 3. Verify LaTeX image was generated
        expect(response.attachments).toHaveLength(1);
        expect(response.attachments[0].mimeType).toBe('image/png');
        
        // 4. Verify Canvas push (if mobile node connected)
        const canvasPush = await gateway.getLastCanvasPush();
        expect(canvasPush.surfaceId).toBe('math-result');
        expect(canvasPush.components).toContainEqual(
            expect.objectContaining({ id: 'latex-display' })
        );
    });
});

3.4 Stress Test: Pi Cluster

#!/bin/bash
# stress_test.sh — Run on Pi cluster control node
# Generate 1000 random expressions and fire them concurrently

for i in $(seq 1 1000); do
    EXPR=$(symclaw-cli random-expr --depth 5 --seed $i)
    curl -s -X POST http://gateway:18789/api/eval \
        -H "Content-Type: application/json" \
        -d "{\"expr\": \"$EXPR\"}" &
    
    # Rate limit: 50 concurrent
    [ $(jobs -r | wc -l) -ge 50 ] && wait -n
done
wait

echo "All 1000 evaluations complete"
# Verify: no crashes, no OOM, all returned valid results

4. Deployment Architecture

4.1 Single-Node (90% of users)

# docker-compose.yml — one command: docker compose up
version: '3.8'
services:
  symclaw:
    image: ghcr.io/symclaw/symclaw:latest
    ports:
      - "18789:18789"  # OpenClaw Gateway
      - "3000:3000"    # WebChat
    volumes:
      - ~/.openclaw:/root/.openclaw
      - ~/.symclaw:/root/.symclaw
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - SYMCLAW_ENGINE=wasm  # or 'native' for full performance
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 2G

4.2 Pi Cluster (Power Users)

┌──────────────────────────────────────────┐
│          Pi 5 (Control Node)              │
│  OpenClaw Gateway + Tailscale             │
│  Load Balancer (round-robin)              │
│  ┌────────┐ ┌────────┐ ┌────────┐       │
│  │ Pi 4 #1│ │ Pi 4 #2│ │ Pi 4 #3│       │
│  │ Engine │ │ Engine │ │ Engine │        │
│  │ Worker │ │ Worker │ │ Worker │        │
│  └────────┘ └────────┘ └────────┘       │
│         ↕ Tailscale mesh ↕               │
│  ┌──────────────────────────────┐        │
│  │  x86 Workstation (optional)  │        │
│  │  RTX 5090 — heavy compute    │        │
│  └──────────────────────────────┘        │
└──────────────────────────────────────────┘

4.3 Nix Deployment

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    rust-overlay.url = "github:oxalica/rust-overlay";
    crane.url = "github:ipetkov/crane";
  };

  outputs = { self, nixpkgs, rust-overlay, crane, ... }:
    let
      systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
    in {
      packages = builtins.listToAttrs (map (system: {
        name = system;
        value = {
          symclaw-core = crane.lib.${system}.buildPackage {
            src = ./core;
            # Cross-compile for Pi from x86
          };
          symclaw-wasm = crane.lib.${system}.buildPackage {
            src = ./wasm;
            CARGO_BUILD_TARGET = "wasm32-unknown-unknown";
          };
        };
      }) systems);
      
      nixosModules.symclaw = { config, ... }: {
        services.symclaw = {
          enable = true;
          port = 18789;
          engineMode = "native"; # or "wasm"
          anthropicApiKey = config.sops.secrets.anthropic.path;
        };
      };
    };
}

5. Open Source & Community Strategy

5.1 Launch Sequence

Week Action Channel
T-2 Soft launch: share with 10 trusted alpha testers Direct invite
T-1 Blog post: "Why We Built an Open-Source Mathematica in Rust" Personal blog + dev.to
T+0 GitHub public + crates.io publish GitHub
T+0 Hacker News "Show HN" post Hacker News
T+0 r/rust, r/math, r/opensource posts Reddit
T+1 OpenClaw Discord announcement OpenClaw community
T+2 Video demo: "From Telegram to LaTeX in 2 Seconds" YouTube + X
T+4 Reach out to university math departments Email + academic networks

5.2 Good First Issues (Pre-Labeled)

  • "Add hyperbolic trig functions (sinh, cosh, tanh)"
  • "Implement pretty-print for matrix expressions"
  • "Add LaTeX input parser (basic subset)"
  • "Write property test for trig identities"
  • "Add Fibonacci sequence to the series module"
  • "Improve error messages for parse failures"
  • "Add --json output flag to CLI"

5.3 Governance

  • License: MIT + Apache 2.0 (dual license, standard Rust ecosystem)
  • Contributions: All PRs require 1 review + CI green + property tests pass
  • Rule contributions: New rewrite rules require (a) correctness proof sketch, (b) proptest coverage, (c) benchmark showing no performance regression
  • Breaking changes: Semantic versioning, deprecation warnings in minor versions

6. What the Roadmap Was Missing — Additions

6.1 Caching Layer (Add to Phase 1)

use lru::LruCache;
use std::sync::Mutex;

// Expression-level memoization
lazy_static! {
    static ref SIMPLIFY_CACHE: Mutex<LruCache<u64, Arc<Expr>>> = 
        Mutex::new(LruCache::new(NonZeroUsize::new(10_000).unwrap()));
}

pub fn simplify_cached(expr: &Expr) -> Arc<Expr> {
    let hash = expr.stable_hash();
    if let Some(cached) = SIMPLIFY_CACHE.lock().unwrap().get(&hash) {
        return cached.clone();
    }
    let result = simplify(expr);
    SIMPLIFY_CACHE.lock().unwrap().put(hash, result.clone());
    result
}

6.2 Confidence Scoring (Add to Phase 2)

Not all simplifications are equally trustworthy. Add a confidence score:

pub struct EvalResult {
    pub expr: Expr,
    pub latex: String,
    pub confidence: Confidence,
    pub steps: Vec<Step>,
}

pub enum Confidence {
    Exact,           // Algebraic simplification, fully verified
    HighConfidence,  // Integration by standard method
    Heuristic,       // Pattern-matched, not formally verified  
    NumericOnly,     // Could not solve symbolically, numeric result
    Failed(String),  // Could not compute, here's why
}

6.3 Offline Mode (Add to Phase 3)

When no LLM is available (no API key, no internet), SymClaw should still work:

User types: /math d/dx(x^2 * sin(x))
→ Direct command parsing (no LLM needed)
→ Engine computes result
→ Returns ASCII: 2x*sin(x) + x^2*cos(x)

User types: "what's the derivative of x squared times sine x"  
→ No LLM available
→ Respond: "Natural language mode requires an AI model connection. 
   Use command syntax: /derive x^2 * sin(x)"

6.4 Benchmark Suite (Add to Phase 5)

Compare against SymPy on standardized problems:

// benchmarks/sympy_parity.rs
const BENCHMARK_PROBLEMS: &[(&str, &str)] = &[
    ("simplify", "(x^2 - 1)/(x - 1)", "x + 1"),
    ("derive", "d/dx(x^3 * sin(x))", "3*x^2*sin(x) + x^3*cos(x)"),
    ("integrate", "∫ x*exp(x) dx", "x*exp(x) - exp(x)"),
    ("solve", "x^2 - 5*x + 6 = 0", "{2, 3}"),
    ("taylor", "sin(x) about 0 order 5", "x - x^3/6 + x^5/120"),
    ("limit", "lim(x→0) sin(x)/x", "1"),
    // ... 100+ problems from MIT OCW
];

6.5 Telemetry & Observability (Add to Phase 4)

// Prometheus metrics exposed at /metrics
pub struct EngineMetrics {
    pub eval_latency: Histogram,      // How long evaluations take
    pub egraph_size: Gauge,           // Current e-graph node count
    pub cache_hit_rate: Counter,      // Memoization effectiveness
    pub parse_errors: Counter,        // Input quality signal
    pub timeout_count: Counter,       // Expressions that hit limits
    pub active_sessions: Gauge,       // Connected OpenClaw sessions
}

Surface these in Omar's OpenClaw Mission Control Dashboard.


7. Timeline Summary

Week  1-2:   Phase 0 — Foundation (CI/CD, Nix, project scaffolding)
Week  3-6:   Phase 1 — Engine Core: Arithmetic, Algebra, Egg, CLI
Week  7-10:  Phase 2 — Engine Core: Calculus, Solving, Series, WASM
Week 11-13:  Phase 3 — OpenClaw Skill, Canvas, Manipulate
Week 14-15:  Phase 4 — Docker, Nix, Pi Cluster, Tailscale
Week 16-18:  Phase 5 — Testing, Docs, Community, V0.1 Alpha Release
─────────────────────────────────────────────────────────────────
Week 19-30:  Phase 6 — V0.5 Beta (LinAlg, ODEs, Jupyter)
Week 31-44:  Phase 7 — V1.0 Launch (GPU, Clawbernetes, Collaboration)

Total to Alpha: ~18 weeks
Total to Production Launch: ~44 weeks


8. Final Recommendation

This project is viable and genuinely differentiated. The combination of:

  1. Rust performance (10-100x over Python CAS)
  2. Equality saturation (provably optimal simplification)
  3. Agentic AI delivery (message your math assistant on WhatsApp)
  4. Edge deployment (Pi cluster, WASM, offline-capable)
  5. Open source (MIT, community-driven)

...creates a product that doesn't exist today. The closest comparison is if Wolfram built Mathematica on top of ChatGPT and gave it away for free — except you own the infrastructure.

Key risk to manage: Scope. Mathematica has 6,600 functions built over 35 years. SymClaw needs to ship V0.1 with ~50 functions that cover 80% of undergraduate math, then let the community build the rest. The architecture (extensible rule sets, community ClawHub skills) makes this feasible.

The paradigm shift isn't the math engine — it's the delivery model. Scientists don't want another desktop app. They want to text their math assistant at 2am from bed and get a correct, beautifully rendered answer on their phone. That's what SymClaw delivers.