I was fed up of going to a task management service and organise my day and goals, hence presenting ManageMe - A workspace and task management dashboard with OpenClaw integration for external channels.
- Node.js 18+
- npm, pnpm, yarn, or bun
- Appwrite instance (self-hosted or cloud)
npm installCreate .env.local:
# Appwrite
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://your-appwrite.cloud
NEXT_PUBLIC_APPWRITE_PROJECT_ID=your-project-id
NEXT_PUBLIC_APPWRITE_DATABASE_ID=your-database-id
NEXT_PUBLIC_APPWRITE_WORKSPACES_ID=workspaces-collection-id
NEXT_PUBLIC_APPWRITE_MEMBERS_ID=members-collection-id
NEXT_PUBLIC_APPWRITE_PROJECTS_ID=projects-collection-id
NEXT_PUBLIC_APPWRITE_TASKS_ID=tasks-collection-id
NEXT_PUBLIC_APPWRITE_FILES_BUCKET_ID=files-bucket-id
NEXT_PUBLIC_APPWRITE_IMAGES_BUCKET_ID=images-bucket-idnpm run devManageMe includes built-in OpenClaw integration for connecting external channels (Discord, Telegram, Slack, etc.) to your workspace.
Follow the OpenClaw installation guide to set up the gateway.
Add to your ~/.openclaw/openclaw.json:
{
"skills": {
"entries": {
"manageme": {
"env": {
"MANAGEME_API_URL": "http://localhost:3000",
"MANAGEME_OPENCLAW_SECRET": "your-secret-here",
"MANAGEME_WORKSPACE_ID": "your-workspace-id"
}
}
}
}
}cp manageme.skill.json ~/.openclaw/skills/manageme/SKILL.mdOr manually create ~/.openclaw/skills/manageme/SKILL.md with the contents of manageme.skill.md.
Example Discord channel setup in openclaw.json:
{
"channels": {
"discord": {
"enabled": true,
"token": {
"source": "env",
"provider": "default",
"id": "DISCORD_BOT_TOKEN"
},
"skills": ["manageme"],
"dm": {
"enabled": true
}
}
}
}export MANAGEME_API_URL="http://localhost:3000"
export MANAGEME_OPENCLAW_SECRET="your-secret-here"
export MANAGEME_WORKSPACE_ID="your-workspace-id"
export DISCORD_BOT_TOKEN="your-discord-token"openclaw startSee how ManageMe works with Discord, file uploads, and real-time updates.
Once connected, you can manage tasks from your channel:
/create task "Review PR" --due 2024-01-15 --priority high
/list tasks
/complete task 123
/upload resource <file> --task 123
See manageme.skill.md for all available commands.
- Task Management: Create, update, complete tasks
- File Attachments: Upload files to tasks (images, PDFs, documents)
- Workspaces: Organize tasks by workspace
- Projects: Group tasks into projects
- Members: Assign tasks to team members
- OpenClaw Integration: Manage tasks from external channels
For external channel integrations:
GET /api/oc/ping- Health checkGET /api/oc/tasks- List tasksPOST /api/oc/task- Create taskPATCH /api/oc/task/{id}/status- Update statusPATCH /api/oc/task/{id}/complete- Complete taskPOST /api/oc/resource- Upload file attachment
For the web interface:
GET /api/tasks- List tasks (with filters)POST /api/tasks- Create taskPATCH /api/tasks/{id}- Update taskDELETE /api/tasks/{id}- Delete taskPOST /api/tasks/{id}/resource- Upload attachmentDELETE /api/tasks/{id}/resource/{fileId}- Delete attachment
- Navigate to a task
- Click "Add File" or drag and drop
- File appears in attachments list
curl -X POST "http://localhost:3000/api/oc/resource?w=workspace-id" \
-H "x-openclaw-secret: your-secret" \
-F "file=@./document.pdf" \
-F "taskId=task-id"- Frontend: Next.js 14 (App Router)
- Styling: Tailwind CSS + Radix UI
- State: TanStack Query
- Forms: React Hook Form + Zod
- Backend: Appwrite (DB, Auth, Storage)
- API: Hono (type-safe routes)
src/
├── app/ # Next.js routes
├── features/ # Feature modules
│ ├── tasks/ # Task management
│ ├── projects/ # Project management
│ ├── workspaces/ # Workspace management
│ └── openclaw/ # OpenClaw integration
├── components/ # Reusable UI
└── lib/ # Utilities
npm run dev # Development server
npm run build # Production build
npm run lint # Lint codeManageMe demonstrates a clean separation between the web interface and external channel integrations:
External Channel (Discord/Telegram/Slack)
↓
OpenClaw Gateway (Authentication, Rate Limiting, Routing)
↓
ManageMe Skill (Command Parsing, Intent Recognition)
↓
Hono API (Type-Safe Endpoints)
↓
Zod Validation (Runtime Type Checking)
↓
Appwrite (Persistence, Real-time Subscriptions)
↓
Web Frontend (React Query Cache)
- Request Reception: OpenClaw receives HTTP POST from channel adapter
- Security Validation: HMAC signature verification, rate limit check
- Routing: Skill router directs to ManageMe handler
- Parsing: Natural language → structured command (action, entity, parameters)
- Validation: Zod schemas ensure data integrity
- Execution: Business logic creates/updates resources
- Response: Formatted for specific channel (Discord embeds, Telegram markdown)
- Propagation: React Query invalidation triggers real-time updates
// Multi-format support
interface UploadHandler {
// multipart/form-data (large files)
handleMultipart(file: File, metadata: Metadata): Promise<UploadResult>;
// application/json (base64 encoded)
handleBase64(data: string, mimeType: string): Promise<UploadResult>;
// application/octet-stream (raw binary)
handleBinary(buffer: ArrayBuffer, filename: string): Promise<UploadResult>;
// text/plain (simple text)
handleText(content: string): Promise<UploadResult>;
}Key Insight: The FormData bug (passing FormData directly to Hono) revealed that browser and Node.js environments handle FormData iteration differently. Solution: pass plain objects, let Hono create FormData internally.
// Appwrite real-time subscriptions
const unsubscribe = databases.subscribe(
"tasks",
["databases.*.collections.*.documents.*"],
(response) => {
// Invalidate React Query cache
queryClient.invalidateQueries({ queryKey: ["tasks"] });
// Optimistic UI updates
queryClient.setQueryData(["tasks"], (old) =>
updateTaskInList(old, response.payload),
);
},
);Enable external services to react to task lifecycle events:
app.post("/webhooks", async (c) => {
const { event, target, conditions } = await c.req.json();
await webhookService.register({
event: "task.created",
target: "https://api.slack.com/webhooks/...",
conditions: { priority: "high" },
});
return c.json({ id: webhookId, status: "active" });
});Automate cross-platform workflows: task created → post to #announcements, PR merged → auto-complete task, file uploaded → backup to cloud storage.
Leverage LLMs for intelligent task extraction from conversations:
app.post("/ai/suggest", async (c) => {
const { context } = await c.req.json();
const completion = await openai.chat.completions.create({
messages: [
{ role: "system", content: "Extract tasks from conversation" },
{ role: "user", content: context },
],
});
return c.json({
suggestions: JSON.parse(completion.choices[0].message.content),
});
});Auto-create tasks from meeting notes, suggest assignees based on expertise, estimate durations from historical data.
Bidirectional sync with GitHub/Linear/Jira:
app.post("/integrations/sync", async (c) => {
const sync = new SyncService(provider, credentials);
await sync.configure({ direction: "bidirectional" });
return c.json({ status: "syncing" });
});Link tasks to PRs/issues, auto-complete on merge, PR status badges in task view, branch creation from tasks.
This project is licensed under the MIT License. See LICENSE for details.
Built with Hand and OpenClaw