AionUi
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
Crawler Summary
A three-agent crewAI system that drafts blog posts in your own writing voice, with a researcher, writer, and voice-checking editor Blog Writing Crew A three-agent $1 system that writes blog posts **in your own voice** — not in the flat, hedge-everything register that LLMs default to when you ask them to "write a blog post." You give it a topic. A **researcher** hunts for an angle worth building a post around, a **writer** drafts it while studying full samples of your actual writing, and an **editor** checks every paragraph back against those sam Capability contract not published. No trust telemetry is available yet. Last updated 10/9/2026.
Freshness
Last checked 10/9/2026
Best For
blog-writing-crew is best for crewai, multi-agent workflows where OpenClaw compatibility matters.
Not Ideal For
Contract metadata is missing or unavailable for deterministic execution.
Evidence Sources Checked
editorial-content, GITHUB REPOS, runtime-metrics, public facts pack
A three-agent crewAI system that drafts blog posts in your own writing voice, with a researcher, writer, and voice-checking editor Blog Writing Crew A three-agent $1 system that writes blog posts **in your own voice** — not in the flat, hedge-everything register that LLMs default to when you ask them to "write a blog post." You give it a topic. A **researcher** hunts for an angle worth building a post around, a **writer** drafts it while studying full samples of your actual writing, and an **editor** checks every paragraph back against those sam
Public facts
4
Change events
1
Artifacts
0
Freshness
Oct 9, 2026
Capability contract not published. No trust telemetry is available yet. Last updated 10/9/2026.
Trust score
Unknown
Compatibility
OpenClaw
Freshness
Oct 9, 2026
Vendor
Niyatinaveennair
Artifacts
0
Benchmarks
0
Last release
Unpublished
Key links, install path, and a quick operational read before the deeper crawl record.
Summary
Capability contract not published. No trust telemetry is available yet. Last updated 10/9/2026.
Setup snapshot
Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.
Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.
Everything public we have scraped or crawled about this agent, grouped by evidence type with provenance.
Vendor
Niyatinaveennair
Protocol compatibility
OpenClaw
Handshake status
UNKNOWN
Crawlable docs
6 indexed pages on the official domain
Merged public release, docs, artifact, benchmark, pricing, and trust refresh events.
Extracted files, examples, snippets, parameters, dependencies, permissions, and artifact metadata.
Extracted files
0
Examples
6
Snippets
0
Languages
python
mermaid
flowchart TD
U["User input<br/>topic + optional personal moment"] --> M["main.py<br/>slugify, load voice samples"]
V["voice_samples.md<br/>(gitignored, local only)"] -->|read from disk| M
M -->|"inputs dict<br/>topic, topic_slug, current_year,<br/>personal_notes, voice_samples"| K["Crew.kickoff()<br/>Process.sequential"]
K --> R["1 - RESEARCHER<br/>find an angle, not a fact pile<br/>verify any stat against 2-3 sources"]
R -->|research brief| W["2 - WRITER<br/>draft while pattern-matching<br/>on full voice samples"]
W -->|draft| E["3 - EDITOR<br/>adversarial check per paragraph:<br/>could anyone have written this?"]
E --> O["Markdown post<br/>written to output/"]python
def load_voice_samples() -> str:
if not VOICE_SAMPLES.exists():
print(f"\nNo voice reference found at {VOICE_SAMPLES}. ...")
return "No voice samples were provided for this author."
return VOICE_SAMPLES.read_text()bash
pip install uv crewai install
bash
cp .env.example .env
bash
cp src/blog_writing_crew/config/voice_samples.template.md \ src/blog_writing_crew/config/voice_samples.md
bash
crewai run
Full documentation captured from public sources, including the complete README when available.
Docs source
GITHUB REPOS
Editorial quality
ready
A three-agent crewAI system that drafts blog posts in your own writing voice, with a researcher, writer, and voice-checking editor Blog Writing Crew A three-agent $1 system that writes blog posts **in your own voice** — not in the flat, hedge-everything register that LLMs default to when you ask them to "write a blog post." You give it a topic. A **researcher** hunts for an angle worth building a post around, a **writer** drafts it while studying full samples of your actual writing, and an **editor** checks every paragraph back against those sam
A three-agent crewAI system that writes blog posts in your own voice — not in the flat, hedge-everything register that LLMs default to when you ask them to "write a blog post."
You give it a topic. A researcher hunts for an angle worth building a post around, a writer drafts it while studying full samples of your actual writing, and an editor checks every paragraph back against those samples and cuts anything that could have been written by anyone.
Output is a markdown post in output/, ready for Substack.
Asking an LLM for a blog post gets you a recognizable artifact: an opening statistic, three tidy body sections, transitions like "moreover" and "in conclusion," and a closing paragraph that summarizes what you just read. It's competent and completely anonymous.
The usual fix — "write casually," "be more conversational" — doesn't work, because those are descriptions of a voice rather than examples of one. The model has no way to ground an abstract adjective in your specific rhythm.
This project's premise is that voice transfer needs three things that a single prompt can't provide at once:
flowchart TD
U["User input<br/>topic + optional personal moment"] --> M["main.py<br/>slugify, load voice samples"]
V["voice_samples.md<br/>(gitignored, local only)"] -->|read from disk| M
M -->|"inputs dict<br/>topic, topic_slug, current_year,<br/>personal_notes, voice_samples"| K["Crew.kickoff()<br/>Process.sequential"]
K --> R["1 - RESEARCHER<br/>find an angle, not a fact pile<br/>verify any stat against 2-3 sources"]
R -->|research brief| W["2 - WRITER<br/>draft while pattern-matching<br/>on full voice samples"]
W -->|draft| E["3 - EDITOR<br/>adversarial check per paragraph:<br/>could anyone have written this?"]
E --> O["Markdown post<br/>written to output/"]
Agents run as a sequential process — each task's output becomes the next task's context. This is deliberate rather than a default: the pipeline is a genuine dependency chain (you can't edit for voice before there's a draft, and you can't draft without an angle), so a hierarchical or parallel process would add coordination overhead with nothing to gain.
Defined declaratively in config/agents.yaml, with tasks in config/tasks.yaml
— prompts live in configuration, not scattered through Python.
Optimizes for an angle, not coverage. The goal explicitly deprioritizes statistics: it hunts for a reframe, a tension, a real story, or a quote worth sitting with, and treats facts as optional. When a topic touches psychology, human behavior, sustainability, animal welfare, ethics, or data science, it's instructed to surface that connection even when it isn't the obvious angle.
Any statistic that does survive must be verified against 2–3 reputable sources, with an explicit instruction never to include something it would have to invent. That's a hallucination guard placed at the only stage where facts enter the pipeline.
Receives the full voice reference and pattern-matches against it. The backstory encodes specific, checkable mechanics rather than vibes:
Runs one adversarial test on every paragraph:
Could any blog writer have written this, or does it sound like her specifically?
Anything generic gets rewritten, not lightly touched. The editor also verifies structural properties the writer was asked for — paragraph cadence, a 5–10 minute read length, an opening that isn't a statistic, an ending that earns its point rather than summarizing — and re-checks that surviving facts are verified.
Separating this from the writer is the important part. Asking one agent to draft and self-critique collapses into it approving its own work.
The most transferable idea here. Rather than describing a target style, the prompts enumerate specific artifacts to remove — each one a known tell of machine-written prose:
| Banned | Why it's a tell | |---|---| | Em dashes, semicolons | Wildly overrepresented in LLM output relative to human casual writing | | "Moreover," "furthermore," "in conclusion" | Formulaic connectives almost nobody uses when writing naturally | | "It's not just X, it's Y" | The three-part parallel construction models fall into constantly | | Opening on a statistic | The default LLM blog opener | | Throat-clearing intros | Padding before the actual idea | | Inflated or unverifiable metrics | Hallucination risk dressed up as authority |
A ban list is enforceable in a way that an aspiration isn't. "Sound more human" gives the editor nothing to check; "cut em dashes on sight" gives it a literal search-and-destroy target. Both the writer and the editor carry the list, so it's applied at generation and at verification.
Voice samples are read in Python, not by the agents. The agents have no
filesystem tools, so main.py reads voice_samples.md and interpolates it into
task descriptions as {voice_samples}:
def load_voice_samples() -> str:
if not VOICE_SAMPLES.exists():
print(f"\nNo voice reference found at {VOICE_SAMPLES}. ...")
return "No voice samples were provided for this author."
return VOICE_SAMPLES.read_text()
Granting file access for one known file would be strictly more capability for strictly no benefit. The missing-file path degrades to a warning plus a placeholder rather than a crash, so a fresh clone still runs end to end — it just produces a generic post, and says so.
Personal details are opt-in and never persisted. The run prompts for an optional "personal moment." The agents are instructed never to invent personal details, so leaving it blank yields a post with no anecdote at all rather than a fabricated one. Whatever you type is used for that run only and never written to disk.
That constraint matters more than it looks. A model asked to write personally will happily manufacture a childhood memory, and in a first-person post published under your name, an invented memory is the worst possible failure.
Requires Python >=3.10 <3.14.
1. Install uv and dependencies
pip install uv
crewai install
2. Add your API key
Get a free Gemini API key at aistudio.google.com/apikey, then:
cp .env.example .env
Paste your key into GEMINI_API_KEY=. .env is gitignored.
Provider-agnostic via LiteLLM — change
MODEL and set that provider's key to use openai/gpt-4o,
anthropic/claude-sonnet-4-5, or anything else LiteLLM supports. No code
changes.
3. Teach it your voice — the step that actually determines output quality
cp src/blog_writing_crew/config/voice_samples.template.md \
src/blog_writing_crew/config/voice_samples.md
Fill it in with two or three complete pieces of your own writing, plus notes on what stays consistent across them. The template walks through each section.
The whole file is loaded into the writer and editor prompts on every run. Full samples produce your voice; vague instructions like "write casually" produce a generic post. It is worth the twenty minutes.
voice_samples.md is gitignored, so your writing stays on your machine.
crewai run
Prompts for a topic and an optional personal moment. The finished post
lands in output/<topic-slug>.md.
Four other entry points are wired up in main.py:
| Command | Purpose |
|---|---|
| crewai run | Interactive single run |
| train | n_iterations training loop for prompt iteration |
| replay | Re-run from a specific task id without redoing earlier stages |
| test | Evaluation run against a separate eval_llm |
| run_with_trigger | Accepts a JSON payload, for webhook or form-driven runs |
replay is the practical one during development — when the editor stage is the
part you're tuning, it skips re-running research and writing.
src/blog_writing_crew/
├── main.py # entry points, input handling, voice-sample loading
├── crew.py # @CrewBase wiring: 3 agents, 3 tasks, sequential
├── config/
│ ├── agents.yaml # roles, goals, backstories (the style rules live here)
│ ├── tasks.yaml # per-task instructions and expected outputs
│ └── voice_samples.template.md # committed template; your filled copy is gitignored
├── tools/
│ └── custom_tool.py # scaffold for adding tools
└── knowledge/
└── user_preference.txt # placeholder preferences (dummy data)
config/agents.yaml — the three agents' roles, goals, backstories. The
writer's backstory carries most of the style rules; this is the highest-leverage
file to edit.config/tasks.yaml — what each agent is asked to do and what it must hand back.crew.py — agent/task wiring and the output path.main.py — inputs and entry points.Gotcha: if you add a new {placeholder} to a YAML config, add it to every
inputs dict in main.py (run, train, test, run_with_trigger) or that
entry point fails on the missing key.
Shipped tuned for reflective, story-driven, philosophical posts: no em dashes or
semicolons, short paragraphs, opens on a concrete moment rather than a
statistic, facts optional. For a different kind of post — technical tutorials,
listicles, reported pieces — edit those preferences in agents.yaml and
tasks.yaml. The architecture is agnostic; only the style rules are opinionated.
Built on the crewAI framework.
Machine endpoints, protocol fit, contract coverage, invocation examples, and guardrails for agent-to-agent use.
Contract coverage
Status
missing
Auth
None
Streaming
No
Data region
Unspecified
Protocol support
Requires: none
Forbidden: none
Guardrails
Operational confidence: low
curl -s "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/snapshot"
curl -s "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/contract"
curl -s "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/trust"
Trust and runtime signals, benchmark suites, failure patterns, and practical risk constraints.
Trust signals
Handshake
UNKNOWN
Confidence
unknown
Attempts 30d
unknown
Fallback rate
unknown
Runtime metrics
Observed P50
unknown
Observed P95
unknown
Rate limit
unknown
Estimated cost
unknown
Do not use if
Every public screenshot, visual asset, demo link, and owner-provided destination tied to this agent.
Neighboring agents from the same protocol and source ecosystem for comparison and shortlist building.
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
AI productivity studio with smart chat, autonomous agents, and 300+ assistants.
The Frontend for Agents & Generative UI. React + Angular
Contract JSON
{
"contractStatus": "missing",
"authModes": [],
"requires": [],
"forbidden": [],
"supportsMcp": false,
"supportsA2a": false,
"supportsStreaming": false,
"inputSchemaRef": null,
"outputSchemaRef": null,
"dataRegion": null,
"contractUpdatedAt": null,
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Invocation Guide
{
"preferredApi": {
"snapshotUrl": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/snapshot",
"contractUrl": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/contract",
"trustUrl": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/trust"
},
"curlExamples": [
"curl -s \"https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/snapshot\"",
"curl -s \"https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/contract\"",
"curl -s \"https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/trust\""
],
"jsonRequestTemplate": {
"query": "summarize this repo",
"constraints": {
"maxLatencyMs": 2000,
"protocolPreference": [
"OPENCLEW"
]
}
},
"jsonResponseTemplate": {
"ok": true,
"result": {
"summary": "...",
"confidence": 0.9
},
"meta": {
"source": "GITHUB_REPOS",
"generatedAt": "2026-10-10T00:12:25.097Z"
}
},
"retryPolicy": {
"maxAttempts": 3,
"backoffMs": [
500,
1500,
3500
],
"retryableConditions": [
"HTTP_429",
"HTTP_503",
"NETWORK_TIMEOUT"
]
}
}Trust JSON
{
"status": "unavailable",
"handshakeStatus": "UNKNOWN",
"verificationFreshnessHours": null,
"reputationScore": null,
"p95LatencyMs": null,
"successRate30d": null,
"fallbackRate": null,
"attempts30d": null,
"trustUpdatedAt": null,
"trustConfidence": "unknown",
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Capability Matrix
{
"rows": [
{
"key": "OPENCLEW",
"type": "protocol",
"support": "unknown",
"confidenceSource": "profile",
"notes": "Listed on profile"
},
{
"key": "crewai",
"type": "capability",
"support": "supported",
"confidenceSource": "profile",
"notes": "Declared in agent profile metadata"
},
{
"key": "multi-agent",
"type": "capability",
"support": "supported",
"confidenceSource": "profile",
"notes": "Declared in agent profile metadata"
}
],
"flattenedTokens": "protocol:OPENCLEW|unknown|profile capability:crewai|supported|profile capability:multi-agent|supported|profile"
}Facts JSON
[
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Niyatinaveennair",
"href": "https://github.com/niyatinaveennair/blog-writing-crew",
"sourceUrl": "https://github.com/niyatinaveennair/blog-writing-crew",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-09T03:20:46.079Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/contract",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-10-09T03:20:46.079Z",
"isPublic": true
},
{
"factKey": "docs_crawl",
"category": "integration",
"label": "Crawlable docs",
"value": "6 indexed pages on the official domain",
"href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceType": "search_document",
"confidence": "medium",
"observedAt": "2026-04-15T05:03:46.393Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/trust",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/crewai-niyatinaveennair-blog-writing-crew/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
]Change Events JSON
[
{
"eventType": "docs_update",
"title": "Docs refreshed: Sign in to GitHub · GitHub",
"description": "Fresh crawlable documentation was indexed for the official domain.",
"href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
"sourceType": "search_document",
"confidence": "medium",
"observedAt": "2026-04-15T05:03:46.393Z",
"isPublic": true
}
]Sponsored
Ads related to blog-writing-crew and adjacent AI workflows.