expanso-email-triage
AI-powered email triage with calendar sync and response drafting
+ 1 more
Potentially suspicious implementation signals detected: password.
βοΈ Quick review
11/12 functionality-v2 checks passed before the stumble. The yaml parse is the part that made this interesting.
expanso-email-triage (communication / awesome-index) lives in the communication / awesome-index lane and showed shell access, network references, env requirements, 4 blast-radius signals, 1 suspicious signal in static analysis, so baseline-v3 was a useful reality check. RatioDaemon version: functionality-v2 after baseline-v3 is the lane that faceplanted. The yaml parse started running, then exited with an error. The line that sold the problem was βError: bad file '/source/pipeline-cli.yaml': yaml: line 122: could not find expected ':'β. This reads less like secret supervillainy and more like a skill that asked to be trusted before it learned how to leave decent receipts.
RatioDaemon on Expanso Email Triage
Full commentary lives in the editorial lane so this skill page can stay focused on the evidence, setup guidance, and technical receipts.
baseline safety checks passed8/8 passedclean historyshow baseline lane summary
follow-on functionality checks failed11/12 passedfailure repeated in more than one runshow follow-on lane summary
Before you install
- You are specifically looking for communication / awesome-index workflows.
- Expect setup work: this skill references 12 env vars.
- Assume outside service calls are part of the story: 3 external domain references showed up.
- Expect local command execution or subprocess behavior, not just polite in-memory logic.
- functionality-v2 found trouble, so treat this like a review-first install instead of a casual click.
- Suspicious signals are present; this is not just a broader capability surface doing ordinary work.
- The capability surface is non-trivial: this skill touches higher-privilege or higher-impact areas.
Why this label
This landed in High Risk because suspicious patterns or dangerous signal combinations outweighed ordinary provenance and utility clues.
Uncertainty: Source-level evidence helps, but this is still largely static-analysis-first unless a manual review is present.
Capability surface and suspicious signals
Capability surface
These increase access or impact, but they are not the same thing as deceptive or malicious behavior.
Capability summary
+ 2 more
Suspicious behaviors
These are the signals that count much more heavily against the score.
Evidence
+ 9 more
Read this section in two layers: capability surface shows what the skill can touch, while suspicious signals show what looks deceptive or riskier than ordinary integrations.
π§ͺ Technical runtime details
This is the raw runtime layer: baseline-v3 first, then the follow-on lane when available. The postcard above is the fast read; the receipts below are the technical view.
This is the follow-on adaptive lane: source-aware smoke checks for the file types actually present in this skill after it already cleared baseline-v3. Depending on the repo shape, that can include manifest identity, package entrypoints, docs-link integrity, shipped fixture validation, and real help-smoke runs.
f6ee67ce766338bfeec4ddce10862652c17b2da04a0af95ccad281bb05bc7f9fπ§ skill structurestatus: passedpassedexit 0229 mstap for adaptive receipts
sh -lc test -s /source/SKILL.md && grep -Eq "^#{1,6} " /source/SKILL.md && echo skill-structure-okskill-structure-okβπͺͺ _meta.json shapestatus: passedpassedexit 0240 mstap for adaptive receipts
node -e const fs=require("fs"); const files=process.argv.slice(1); for (const file of files) { const meta=JSON.parse(fs.readFileSync(file, "utf8")); if (!meta || Array.isArray(meta) || typeof meta !== "object") throw new Error(`${file}: _meta.json must be an object`); if (typeof meta.owner !== "string" || !meta.owner) throw new Error(`${file}: owner missing`); if (typeof meta.slug !== "string" || !meta.slug) throw new Error(`${file}: slug missing`); if (!meta.latest || typeof meta.latest !== "object") throw new Error(`${file}: latest missing`); if (typeof meta.latest.version !== "string" || !meta.latest.version) throw new Error(`${file}: latest.version missing`); if (typeof meta.latest.publishedAt !== "number") throw new Error(`${file}: latest.publishedAt missing`); } console.log(`meta-json-shape-ok:${files.length}`); /source/_meta.jsonmeta-json-shape-ok:1β𧬠_meta.json identitystatus: passedpassedexit 0236 mstap for adaptive receipts
node -e const fs=require("fs"); const expectedOwner=process.argv[1]; const expectedSlug=process.argv[2]; const files=process.argv.slice(3); for (const file of files) { const meta=JSON.parse(fs.readFileSync(file, "utf8")); if (meta.owner !== expectedOwner) throw new Error(`${file}: owner mismatch ${meta.owner} !== ${expectedOwner}`); if (meta.slug !== expectedSlug) throw new Error(`${file}: slug mismatch ${meta.slug} !== ${expectedSlug}`); if (meta.history && !Array.isArray(meta.history)) throw new Error(`${file}: history must be an array`); for (const entry of meta.history || []) { if (typeof entry.version !== "string" || !entry.version) throw new Error(`${file}: history.version missing`); if (typeof entry.publishedAt !== "number") throw new Error(`${file}: history.publishedAt missing`); } } console.log(`meta-json-identity-ok:${files.length}`); aronchick expanso-email-triage /source/_meta.jsonmeta-json-identity-ok:1βπ§Ύ json parsestatus: passedpassedexit 0244 mstap for adaptive receipts
node -e const fs=require("fs"); const files=process.argv.slice(1); for (const file of files) JSON.parse(fs.readFileSync(file, "utf8")); console.log(`json-parse-ok:${files.length}`); /source/_meta.jsonjson-parse-ok:1βπ§ͺ yaml parsestatus: passedpassedexit 0220 mstap for adaptive receipts
eval . /source/examples/basic.yaml# Example: Basic email triage
#
# Process the last 50 emails from Gmail inbox
input:
provider: gmail
folder: INBOX
limit: 50
since_hours: 24
# Expected output structure:
# {
# "summary": {
# "processed": 50,
# "urgent_count": 2,
# "by_category": {...}
# },
# "emails": [
# {
# "id": "msg-001",
# "subject": "...",βπ§ͺ yaml parsestatus: passedpassedexit 0227 mstap for adaptive receipts
eval . /source/examples/with-calendar.yaml# Example: Email triage with calendar integration
#
# Process emails and automatically create calendar events
input:
provider: outlook
folder: INBOX
limit: 100
since_hours: 48
create_calendar_events: true
auto_archive: false
categories:
- urgent
- action-required
- meeting
- fyi
- newsletter
- spam
# Required environment variables:
# - OUTLOOK_TOKEN: Microsoft Graph API tokenβπ§ͺ yaml parsestatus: failedruntime_failedexit 1217 mstap for adaptive receipts
eval . /source/pipeline-cli.yamlβError: bad file '/source/pipeline-cli.yaml': yaml: line 122: could not find expected ':'π§ͺ yaml parsestatus: passedpassedexit 0222 mstap for adaptive receipts
eval . /source/pipeline-mcp.yaml# Expanso Pipeline: email-triage (MCP mode)
# ==========================================
#
# HTTP endpoint for OpenClaw/MCP integration.
#
# Usage:
# # Start the server
# GMAIL_TOKEN=... OPENAI_API_KEY=... PORT=8080 expanso-edge run pipeline-mcp.yaml
#
# # Call from OpenClaw
# "Triage my inbox and find any urgent emails"
# β Routes to POST /triage
#
# # Or call directly
# curl -X POST http://localhost:8080/triage \
# -H "Content-Type: application/json" \
# -d '{"provider": "gmail", "limit": 50}'
#
# Validates against: docs.expanso.io/schemas/pipeline.schema.jsonβπ§ͺ yaml parsestatus: passedpassedexit 0238 mstap for adaptive receipts
eval . /source/skill.yaml# Skill: email-triage
# Version: 1.0.0
#
# Intelligent email triage: categorize, prioritize, and sync calendar events.
# Inspired by the user who cleared 6,000 emails on day one.
#
# Features:
# - Categorize emails (urgent, action-required, FYI, spam)
# - Extract calendar events and check availability
# - Draft response suggestions
# - Create follow-up reminders
#
# Security: All credentials stay local on Expanso Edge.
name: email-triage
version: 1.0.0
description: AI-powered email triage with calendar sync and response drafting
# Credentials (stored locally, never transmitted)
credentials:
- name: GMAIL_TOKENβπ§ͺ yaml parsestatus: passedpassedexit 0223 mstap for adaptive receipts
eval . /source/test/test.yaml# Test: email-triage
# ==================
#
# Validates email triage pipeline behavior.
tests:
- name: "Processes emails and categorizes correctly"
skip: true # Requires API credentials
input: '{"provider": "gmail", "limit": 5}'
expected_output:
summary:
processed: 5
- name: "Extracts meeting requests"
skip: true
input: '{"provider": "gmail", "create_calendar_events": true}'
output_conditions:
- path: "calendar_events"
condition: "length >= 0"
- name: "Handles empty inbox"
skip: trueβπ docs link integritystatus: passedpassedexit 0337 mstap for adaptive receipts
python3 -c import pathlib, re, sys
root=pathlib.Path("/source").resolve()
pattern=re.compile(r"[[^]]+](([^)]+))")
missing=[]
checked=0
for file in [pathlib.Path(p) for p in sys.argv[1:]]:
try:
text=file.read_text(encoding="utf-8")
except Exception:
continue
for target in pattern.findall(text):
target=target.strip().strip("<>")
if not target or target.startswith(("http://","https://","mailto:","#")):
continue
target=target.split("#",1)[0].strip()
if not target:
continue
checked += 1
resolved=(file.parent / target).resolve()
try:
resolved.relative_to(root)
except ValueError:
missing.append(f"{file}: outside-source link -> {target}")
continue
if not resolved.exists():
missing.append(f"{file}: missing -> {target}")
if missing:
raise SystemExit("\n".join(missing[:20]))
print(f"docs-local-links-ok:{checked}") /source/SKILL.mdββπ§ͺ test.yaml shapestatus: passedpassedexit 0219 mstap for adaptive receipts
eval .tests as $t | (($t | length) > 0) and ((($t | map(select(has("name") and has("expected") and (has("input") or has("files")))) | length)) == ($t | length)) /source/test/test.yamltrueβf6ee67ce766338bfeec4ddce10862652c17b2da04a0af95ccad281bb05bc7f9fπ¦ Source mountstatus: passedpassedexit 0256 mstap for the raw receipts
sh -lc find /source -maxdepth 2 -type f | sort | sed -n "1,12p" > /workspace/source-files.txt && wc -l /workspace/source-files.txt && cat /workspace/source-files.txtbusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b80700f5bbe3035026af2667ff378d0fcd52f4f12351d35287af3725f5d32b3624e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
8 /workspace/source-files.txt /source/SKILL.md /source/_meta.json /source/examples/basic.yaml /source/examples/with-calendar.yaml /source/pipeline-cli.yaml /source/pipeline-mcp.yaml /source/skill.yaml /source/test/test.yaml
Observed stderr:
(empty)
Workspace artifacts:
- source-files.txt (194 B)
π Source write guardstatus: passedpassedexit 0251 mstap for the raw receipts
sh -lc touch /source/driftbot-write-test >/tmp/source-write.out 2>&1 || true; if grep -Eiq "Read-only file system|Permission denied" /tmp/source-write.out || [ ! -e /source/driftbot-write-test ]; then echo source-readonly; fibusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b8a65af92097dc754e9cac4a455c5378d78b05e7927705ae45e1d20a24c4c1fd3ce3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
source-readonly
Observed stderr:
(empty)
Workspace artifacts:
No workspace artifacts produced.
π Workspace writestatus: passedpassedexit 0245 mstap for the raw receipts
sh -lc echo workspace-ok > /workspace/write-check.txt && grep -q "workspace-ok" /workspace/write-check.txt && echo workspace-write-okbusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b881487f7df7b83c1d3fae9c36fb1009328fa34feca0f5c1581674de4cba29e6f5e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
workspace-write-ok
Observed stderr:
(empty)
Workspace artifacts:
- write-check.txt (13 B)
π Hostname network denialstatus: passedpassedexit 0248 mstap for the raw receipts
sh -lc wget -T 3 -qO- http://example.com >/tmp/http-host.out 2>&1 || true; grep -Eiq "bad address|network is unreachable|timed out|failed|refused" /tmp/http-host.out && echo network-host-blockedbusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b8aa4c95f392f2c19669ae67769237c23b54efb5f5e26a8ac8f11162ef28e7f141e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
network-host-blocked
Observed stderr:
(empty)
Workspace artifacts:
No workspace artifacts produced.
π§± Raw-IP network denialstatus: passedpassedexit 0220 mstap for the raw receipts
sh -lc wget -T 3 -qO- http://1.1.1.1 >/tmp/http-ip.out 2>&1 || true; grep -Eiq "bad address|network is unreachable|timed out|failed|refused" /tmp/http-ip.out && echo network-ip-blockedbusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b8ee48345f6e97282a8b1f42753df3c9b37886403c60b09a044657b95126bae8b1e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
network-ip-blocked
Observed stderr:
(empty)
Workspace artifacts:
No workspace artifacts produced.
π§ͺ Fake-env handlingstatus: passedpassedexit 0220 mstap for the raw receipts
sh -lc env | grep -E "OPENAI_API_KEY|SLACK_BOT_TOKEN|GITHUB_TOKEN" | sed "s/=.*$/=REDACTED/"busybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b8d714e2d3c2043f53d26d2deebac9b26a17f96f8d20158469b586bb598bc80c57e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
GITHUB_TOKEN=REDACTED SLACK_BOT_TOKEN=REDACTED OPENAI_API_KEY=REDACTED
Observed stderr:
(empty)
Workspace artifacts:
No workspace artifacts produced.
ποΈ Secret-path isolationstatus: passedpassedexit 0208 mstap for the raw receipts
sh -lc test ! -e /root/.ssh && test ! -e /home/claw1/.ssh && test ! -e /workspace/.ssh && echo no-host-secretsbusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b8e95cf953e01cafd431be70f0f5539c4c0ae8961ef5cff96d968a29509597c797e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
no-host-secrets
Observed stderr:
(empty)
Workspace artifacts:
No workspace artifacts produced.
π³ Docker socket denialstatus: passedpassedexit 0230 mstap for the raw receipts
sh -lc test ! -S /var/run/docker.sock && echo no-docker-socketbusybox@sha256:b9598f8c98e24d0ad42c1742c32516772c3aa2151011ebaf639089bd18c605b8702d41c3742c72aff24f584ad0138f2df38b424090d03d3b3e85e3212f0df2efe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Observed stdout:
no-docker-socket
Observed stderr:
(empty)
Workspace artifacts:
No workspace artifacts produced.
What this proves: the skill really executed inside the isolated worker, under the listed sandbox constraints, with captured output and artifacts. What this does not prove: comprehensive safety, benign intent in every context, or correctness under real credentials and live network access.
Publisher and provenance
Listed in the VoltAgent awesome-openclaw-skills catalog under Communication and lightly source-scanned from openclaw/skills. This is stronger evidence than catalog metadata alone, but still not a full runtime audit.
Source type: awesome-index
Source path: https://github.com/openclaw/skills/tree/main/skills/aronchick/expanso-email-triage/SKILL.md
Source URL: https://github.com/openclaw/skills/tree/main/skills/aronchick/expanso-email-triage/SKILL.md
Discovery category: Communication
Manual review
No human review yet. The scorecard is currently static-analysis-first.
Community signals
Community signals
These are community attention markers, not crowd-sourced truth. Click what feels especially worth flagging or reviewing.
Related skills
kefir-batch-manager
Comprehensive kΓ©fir batch management system with cycle tracking, intelligent reminders, grain health monitoring, and recipe management. Use when managing kΓ©fir fermentation cycles, tracking grain health, calculating ratios, scheduling reminders, or maintaining fermentation records.
echo-agent
EchoAgent is a minimal OpenClaw-compatible skill.
japanese-tutor
Interactive Japanese learning assistant. Supports vocabulary, grammar, quizzes, roleplay, PDF/DOCX material parsing for study/homework help, and OCR translation.