Disculate
A discord friendly calculator tool.
Comandos que añade este plugin
Acerca de este plugin
Disculate
An in-Discord calculator plugin for YourBot. Arithmetic, percentages, common math functions, and constants — without leaving the channel.
You:
/calc expression: (3 + 4) * sqrt(16)Disculate:
(3 + 4) * sqrt(16)= 28
Built for the YourBot platform's sandboxed plugin runtime (yourbot_sdk; the platform was formerly branded "MMO Maid"). Safe-tier capabilities only (interaction:respond, storage:kv). No outbound HTTP, no disk writes, no eval/exec/compile on user input.
Slash commands
| Command | Who | Purpose |
|---|---|---|
/calc expression:<text> [ephemeral:<bool>] |
Anyone | Evaluate a math expression. ephemeral:true hides the result from the channel. |
/calc-config [precision:<int>] [angle_mode:<rad|deg>] [scientific_threshold:<int>] |
Server admin (MANAGE_GUILD) |
Set per-server defaults. Omitted options keep their current value. |
/calc-help |
Anyone | Quick reference for syntax, functions, and constants. |
Supported syntax
Operators: + - * / // ** unary +/- parentheses
Percent: trailing % divides by 100 (e.g. 50% → 0.5, 200 * 5% → 10)
Constants (case-sensitive): pi e tau
Functions:
| Category | Names |
|---|---|
| Basic | abs(x) round(x[, n]) floor(x) ceil(x) min(a, b, ...) max(a, b, ...) mod(a, b) pow(a, b) gcd(a, b) lcm(a, b) trunc(x) hypot(x, y) sign(x) |
| Roots / exp / log | sqrt(x) cbrt(x) exp(x) log(x[, base]) log10(x) log2(x) ln(x) |
Trig (honours angle_mode) |
sin cos tan asin acos atan atan2(y, x) |
| Hyperbolic | sinh(x) cosh(x) tanh(x) asinh(x) acosh(x) atanh(x) |
Examples
| Input | Output |
|---|---|
2 + 2 |
= 4 |
1/3 |
= 0.333333 (precision-dependent) |
200 * 5% |
= 10 |
100 + 10% |
= 100.1 (10% = 0.1, not "10% of 100"; see ARCHITECTURE.md §B) |
sqrt(2) |
= 1.414214 |
sin(30) with angle_mode:deg |
= 0.5 |
mod(-7, 3) |
= 2 (sign-of-divisor) |
(2+1)*7-8 |
= 13 with a Steps field showing the three intermediate computations |
1e308 * 10 |
error: Result is too large to represent. |
2^3 |
error: Use ** for power, not ^ (which would be bitwise XOR). |
5 % 3 |
error: Use mod(a, b) for modulo. Trailing % means percent (e.g. 50% = 0.5). |
sqirt(2) |
error: Unknown function sqirt. Did you mean sqrt? |
Pi + 1 |
error: Unknown name Pi. Constants are case-sensitive. Did you mean pi? |
((1+2) |
error: Unclosed parenthesis. 1 more ( than ). Add 1 ) to balance the expression. |
sqrt(-1) |
error: sqrt of a negative value isn't a real number. Try sqrt(abs(x)) if you want the magnitude. |
Errors aren't generic. Disculate identifies the specific problem in your input — close-typo suggestions for unknown names and functions, paren-balance counts, function-specific domain explanations, operator-mistake hints. Every error embed shows what's wrong on top, how to fix it next, a reason: <code> footer for tracking, and a Show help button that swaps the error for the full syntax reference in place — one message, not two.
/calc-help leads with a Commands overview and adapts to the server: a fresh install (nothing configured yet) sees a numbered Getting started quick-start; a configured server sees its live Server settings. Running /calc-config with no options shows the current settings plus a one-click Switch to degrees / radians button so an admin can fix the most common trig surprise without learning the option syntax.
Configuration
/calc-config adjusts three per-server settings, persisted in plugin KV:
| Setting | Range | Default |
|---|---|---|
precision |
0–10 decimal places |
6 |
angle_mode |
rad / deg |
rad |
scientific_threshold |
1–20 (switch to scientific notation when |result| ≥ 10^N) |
12 |
A per-user cooldown of 2 seconds prevents accidental spam. Errors are always shown ephemerally to the invoker only.
Safety model
- No
eval/exec/compileon user input. The parser uses stdlibast.parse(mode="eval")and a manual node-allowlist walker. The audit gate (tools/run_audit.py) scans for these calls and blocks any from being committed. - Defense-in-depth DoS guards: 120-char input cap, 32-deep AST cap, 200-node AST cap,
**operand guard that routes large operands throughmath.pow(so bignums can't OOM the sandbox), and a 200 ms wall-clock budget. - Mention injection defeated at two layers:
safe_textinserts zero-width spaces between@andeveryone/here, and every response setsallowed_mentions: {"parse": []}. - NFKC normalisation + bidi/control-char rejection on every input before parsing.
See AUDIT-REPORT.md for the full audit trail.
Local development
# Requirements: Python 3.11+ (tested on 3.11–3.14)
# Dev deps (test runner + the SDK whose vendored validator the audit uses):
py -m pip install -r requirements-dev.txt
# Run the test suite (333 tests, ~0.2s)
py -m pytest tests/ -q
# Build the deterministic production bundle (build/disculate.zip)
py tools/build_bundle.py
# Run all 9 audit gates (manifest, imports, blocked_substrings, no_eval_ast,
# todo_markers, plugin_run, pytest, bundle,
# platform_validator)
py tools/run_audit.py
The bundle excludes everything outside an explicit allowlist (see tools/build_bundle.py:INCLUDED_FILES). Tests, tools, documentation, dotfiles, and assets/ never ship — Discord fetches the brand image directly from the GitHub raw URL.
Project layout
disculate/
├── manifest.json ← plugin id, capabilities, slash commands
├── __main__.py ← entry point the platform requires; just imports plugin
├── plugin.py ← handler entry points (must end with plugin.run())
├── assets/
│ └── disculate.webp ← brand thumbnail, referenced by Discord via GitHub raw URL
├── lib/
│ ├── parser.py ← cleaning, percent preprocessing, ast.parse + allowlist walker
│ ├── walker.py ← AST walk, DoS guards, wall-clock budget, step trace
│ ├── functions.py ← FunctionSpec registry (one entry per math function)
│ ├── format.py ← result formatting (precision, scientific, int preservation)
│ ├── config.py ← per-server KV config + schema versioning
│ ├── embed.py ← response builders + safe_text/clip/help generation
│ ├── diagnostics.py ← per-reason error explainer + did-you-mean
│ ├── reasons.py ← reason codes + user-facing hints
│ └── logctx.py ← request_id ContextVar for log correlation
├── tests/ ← 333 tests: smoke, unit, handler, failure-injection, adversarial,
│ diagnostics, bundle/platform contract, drift guards, components
├── tools/
│ ├── build_bundle.py ← deterministic zip with allowlist guard
│ ├── run_audit.py ← 9 audit gates (incl. marketplace-substring mirror)
│ └── validate_artifact.py ← runs the platform's vendored upload validator on the zip
└── docs (CLAUDE.md, AUDIT-REPORT.md, ARCHITECTURE.md, RUNBOOK.md, SDK-ASSUMPTIONS.md, CHANGELOG.md)
Documentation
| Document | Audience |
|---|---|
| README.md | Users + first-time contributors. You are here. |
| CLAUDE.md | The next maintainer (or LLM). TL;DR, recipes, things-that-look-wrong-but-aren't. |
| ARCHITECTURE.md | Why each design decision beat its alternatives. |
| AUDIT-REPORT.md | Full audit trail across R1, R2, R3, and the math-shape Tailored round. |
| SDK-ASSUMPTIONS.md | Every defensive try/except that exists because the SDK doc was incomplete — the post-deploy probe list. |
| RUNBOOK.md | Operational scenarios: OOM, KV quota, schema migration, rollback. |
| CHANGELOG.md | Per-version Added / Changed / Fixed. |
Contributing
The single-paragraph recipe for "add a math function" is in CLAUDE.md → Common task recipes. The audit gates in tools/run_audit.py are the merge bar: if py tools/run_audit.py exits non-zero, the change isn't shippable.
Before opening a PR:
py -m pytest tests/ -q # all green
py tools/run_audit.py # all 9 gates pass
License
This repository ships without a LICENSE file. Under default GitHub / copyright terms that means all rights reserved to the author — the source is publicly readable, but redistribution, derivative works, and commercial use are not granted. A formal open-source license may be added later; until then, please open an issue if you'd like to use any of this code outside the context of forking + contributing back.
Plugins relacionados
¿Tienes alguna pregunta?
Pregunta directamente al desarrollador de Disculate. Inicia sesión con Discord para enviar tu pregunta. Se te notificará cuando respondan.
Inicia sesión para preguntar al desarrollador →¿Listo para instalar Disculate?
Inicia sesión con Discord, configura tu servidor y añádelo en minutos.
Instalar en tu servidor →