// >
| name | appflowy-integration |
| description | Integration with AppFlowy project management tool for task tracking, database management, and workspace organization. Use when working with AppFlowy, managing project tasks, creating databases, organizing workspaces, syncing agent work with project tracking, syncing documentation or tasks to AppFlowy, setting up automated sync workflows, or when the user mentions AppFlowy, project tracking, task management, or sync automation. Includes generic sync script that works with ANY project. Supports rich text formatting (bold, italic, code, links, strikethrough) and git pushsync workflow for automated syncing. |
| version | 2.4.0 |
| author | AI Agents Team |
| category | custom |
| token_estimate | ~1500 |
Prerequisites:
requests library installedDo NOT use when:
<quick_start> AI Agents Workspace Configuration:
export APPFLOWY_API_URL="https://appflowy.ark-node.com"
export APPFLOWY_WORKSPACE_ID="c9674d81-6037-4dc3-9aa6-e2d833162b0f"
export APPFLOWY_DOCS_PARENT_ID="c7f9f933-ca10-4206-8be4-a2967f1085aa"
Credentials Location:
/Users/sunginkim/GIT2/ArkNode-AI/projects/appflowy-deployment/.envAccess:
Git PushSync Workflow (Recommended):
# Push to GitHub and auto-sync to AppFlowy
git add .
git commit -m "docs: update documentation"
git pushsync # Push + sync to AppFlowy in one command
Mapping File:
Create appflowy-mapping.yaml to prevent duplicate pages:
mappings:
README.md: page-id-here
docs/guide.md: another-page-id
Generic Project Sync (Any Repository):
# Sync with config file (uses mapping file if present)
python3 sync_project.py --config appflowy-sync.yaml
# Auto-discover and sync documentation
python3 sync_project.py --auto-discover --parent "Documentation"
# Sync specific folder
python3 sync_project.py --source docs/ --parent "API Docs"
# Preview before syncing (dry run)
python3 sync_project.py --config appflowy-sync.yaml --dry-run
# Force re-sync all files
python3 sync_project.py --config appflowy-sync.yaml --force
AI_agents Specific Sync Scripts:
# Sync AI_agents documentation to AppFlowy
cd skills/custom/appflowy-integration/scripts/
python3 sync_docs.py
# Sync AI_agents tasks to AppFlowy Kanban
python3 sync_tasks.py
# Preview before syncing (dry run)
python3 sync_docs.py --dry-run
python3 sync_tasks.py --dry-run
# Force re-sync all items
python3 sync_docs.py --force
python3 sync_tasks.py --force
Environment Variables:
export APPFLOWY_API_URL="https://appflowy.ark-node.com"
export APPFLOWY_API_TOKEN="your_jwt_token"
export APPFLOWY_WORKSPACE_ID="22bcbccd-9cf3-41ac-aa0b-28fe144ba71d"
export APPFLOWY_DOCS_PARENT_ID="parent_page_id" # Optional: Parent page for docs
export APPFLOWY_DATABASE_ID="bb7a9c66-8088-4f71-a7b7-551f4c1adc5d"
Python Client Quick Start:
from appflowy_client import AppFlowyClient
# Initialize client (uses environment variables)
client = AppFlowyClient()
# List workspaces
workspaces = client.list_workspaces()
# List databases in workspace
databases = client.list_databases(client.workspace_id)
# Get database fields
fields = client.get_database_fields(client.workspace_id, database_id)
# Create a task
task = client.create_row(
workspace_id=client.workspace_id,
database_id=database_id,
data={
'title': 'Implement user authentication',
'status': 'In Progress',
'priority': 'High',
'assignee': 'AI Agent',
'description': 'Add JWT-based authentication'
}
)
For detailed workflows, see:
workflows/sync-documentation.md - Sync AI_agents docs to AppFlowyworkflows/sync-tasks.md - Sync AI_agents tasks to Kanban boardworkflows/git-sync.md - Automated sync with git hooks and cronworkflows/task-management.md - Creating and updating tasksworkflows/workspace-operations.md - Workspace and database setupworkflows/troubleshooting.md - Common issues and solutionsreferences/api-reference.md - Complete API documentation
</quick_start><success_criteria>
<api_endpoints> Correct API Endpoints for Page Management:
AppFlowy uses a block-based Delta format for page content, NOT raw markdown. You must create pages first, then append content blocks.
1. Create Page (Empty):
POST /api/workspace/{workspace_id}/page-view
{
"name": "Page Title",
"layout": 0, // 0 = Document layout
"parent_view_id": "parent_id" // Optional: for nested pages
}
Response: {"data": {"view_id": "...", "database_id": null}, "code": 0}
2. Append Content Blocks:
POST /api/workspace/{workspace_id}/page-view/{page_id}/append-block
{
"blocks": [
{"type": "heading", "data": {"level": 1, "delta": [{"insert": "Title"}]}},
{"type": "paragraph", "data": {"delta": [{"insert": "Text content"}]}},
{"type": "bulleted_list", "data": {"delta": [{"insert": "List item"}]}},
{"type": "numbered_list", "data": {"delta": [{"insert": "Numbered item"}]}},
{"type": "code", "data": {"language": "python", "delta": [{"insert": "code"}]}},
{"type": "quote", "data": {"delta": [{"insert": "Quote text"}]}}
]
}
3. Update Page Metadata (Name/Icon only):
PATCH /api/workspace/{workspace_id}/page-view/{page_id}
{
"name": "Updated Title"
}
Note: PATCH does NOT update content. Use append-block endpoint for content.
Delta Block Format: AppFlowy uses Delta format (compatible with Quill.js):
type (heading, paragraph, bulleted_list, numbered_list, code, quote)data containing delta array with {"insert": "text"} objectslevel field (1-6)language fieldMarkdown to Blocks Converter:
Use the markdown_to_blocks() function from update_page_content.py:
from update_page_content import markdown_to_blocks
# Convert markdown to AppFlowy blocks
blocks = markdown_to_blocks(markdown_content)
# Append to page
append_blocks_to_page(api_url, workspace_id, page_id, blocks, token)
Supported markdown elements:
code, links, Documentation Sync โ workflows/sync-documentation.md
Task Sync โ workflows/sync-tasks.md
Git Sync Automation โ workflows/git-sync.md
Task Management โ workflows/task-management.md
Workspace Operations โ workflows/workspace-operations.md
Server Management โ workflows/server-deployment.md
Troubleshooting โ workflows/troubleshooting.md
API Reference โ references/api-reference.md
Method 2: Environment Variables
export APPFLOWY_API_URL="https://appflowy.ark-node.com"
export APPFLOWY_API_TOKEN="your_jwt_token_here"
export APPFLOWY_WORKSPACE_ID="your_workspace_id"
Python Client Configuration:
import os
import requests
class AppFlowyClient:
def __init__(self):
self.api_url = os.getenv('APPFLOWY_API_URL')
self.token = os.getenv('APPFLOWY_API_TOKEN')
self.workspace_id = os.getenv('APPFLOWY_WORKSPACE_ID')
self.headers = {
'Authorization': f'Bearer {self.token}',
'Content-Type': 'application/json'
}
def _make_request(self, method, endpoint, **kwargs):
"""Make authenticated API request."""
url = f"{self.api_url}{endpoint}"
response = requests.request(method, url, headers=self.headers, **kwargs)
response.raise_for_status()
return response.json()
See references/api-reference.md for complete authentication documentation.
<error_handling> Robust Error Handling Pattern:
import logging
from requests.exceptions import RequestException, HTTPError
logger = logging.getLogger(__name__)
def safe_api_call(func):
"""Decorator for safe API calls with error handling."""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except HTTPError as e:
if e.response.status_code == 401:
logger.error("Authentication failed - check API token")
raise Exception("AppFlowy authentication failed")
elif e.response.status_code == 403:
logger.error("Permission denied - check workspace access")
raise Exception("Permission denied for AppFlowy resource")
elif e.response.status_code == 404:
logger.error(f"Resource not found: {e.request.url}")
raise Exception("AppFlowy resource not found")
else:
logger.error(f"API error: {e}")
raise
except RequestException as e:
logger.error(f"Network error connecting to AppFlowy: {e}")
raise Exception("Failed to connect to AppFlowy instance")
return wrapper
# Apply to API methods
@safe_api_call
def create_row_safe(client, workspace_id, database_id, data):
return create_row(client, workspace_id, database_id, data)
Rate Limiting:
import time
from functools import wraps
def rate_limit(calls_per_minute=60):
"""Rate limit API calls to avoid overwhelming server."""
min_interval = 60.0 / calls_per_minute
last_called = [0.0]
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
elapsed = time.time() - last_called[0]
left_to_wait = min_interval - elapsed
if left_to_wait > 0:
time.sleep(left_to_wait)
result = func(*args, **kwargs)
last_called[0] = time.time()
return result
return wrapper
return decorator
See workflows/troubleshooting.md for specific error scenarios and solutions.
</error_handling>
<best_practices> Never hardcode credentials. Use environment variables or secure credential storage.
from dotenv import load_dotenv
load_dotenv()
# Credentials loaded from .env file
api_token = os.getenv('APPFLOWY_API_TOKEN')
**Cache workspace and database IDs** to avoid repeated lookups.
class AppFlowyManager:
def __init__(self):
self.client = AppFlowyClient()
self._workspace_cache = None
self._database_cache = {}
def get_workspace_id(self):
if not self._workspace_cache:
workspaces = list_workspaces(self.client)
self._workspace_cache = workspaces[0]['id']
return self._workspace_cache
def get_database_id(self, database_name):
if database_name not in self._database_cache:
databases = list_databases(self.client, self.get_workspace_id())
db = next((d for d in databases if d['name'] == database_name), None)
if db:
self._database_cache[database_name] = db['id']
return self._database_cache.get(database_name)
**Validate field compatibility** before inserting data.
def validate_task_data(client, workspace_id, database_id, task_data):
"""Ensure task data matches database schema."""
fields = get_database_fields(client, workspace_id, database_id)
field_names = {f['name'] for f in fields}
# Remove fields that don't exist in database
validated = {k: v for k, v in task_data.items() if k in field_names}
# Warn about missing fields
missing = set(task_data.keys()) - field_names
if missing:
logger.warning(f"Fields not in database: {missing}")
return validated
**Medium Freedom:** Follow authentication and API endpoint patterns exactly. Implement error handling and rate limiting. Customize workflow functions based on your project needs.
<security_checklist>
Issue: Tasks created via REST API may not appear in the AppFlowy UI right away.
Cause: AppFlowy requires view objects (Grid, Board, Calendar) to exist as separate collab records in PostgreSQL. The REST API cannot create these view-database associations - only the UI can.
Symptoms:
[useViewOperations] databaseId not found for viewSolution:
Browser Console Workaround:
// This uses your existing session (no auth needed)
const WORKSPACE_ID = '22bcbccd-9cf3-41ac-aa0b-28fe144ba71d';
const DATABASE_ID = 'bb7a9c66-8088-4f71-a7b7-551f4c1adc5d';
fetch(`/api/workspace/${WORKSPACE_ID}/database/${DATABASE_ID}/row`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
cells: {
phVRgL: 'Task Title', // Description field
YAgo8T: 'Task details', // Text field
SqwRg1: 'CEZD' // Status: To Do
}
})
})
.then(r => r.json())
.then(d => console.log('Created:', d.data));
Reference: See workflows/troubleshooting.md for detailed diagnosis and solutions.
<anti_patterns> โ Don't: Continue using expired JWT tokens, causing 401 errors
โ Do: Implement token refresh logic or re-authenticate automatically
if response.status_code == 401:
token = refresh_jwt_token()
retry_request()
โ **Don't:** Hardcode workspace IDs or use wrong IDs
โ Do: List and verify resources first, use descriptive variable names
workspaces = client.list_workspaces()
arknode_workspace = next(w for w in workspaces if w['name'] == 'ArkNode Infrastructure')
workspace_id = arknode_workspace['id']
โ **Don't:** Expect API-created tasks to appear in UI without views
โ Do: Create views in UI first, then use API for task operations
See workflows/troubleshooting.md for view-database association issue.
โ
Do: Use docker compose down && docker compose up -d to recreate containers
# WRONG - doesn't reload .env
docker compose restart
# RIGHT - recreates containers with new .env
docker compose down
docker compose up -d
โ **Don't:** Assume AppFlowy is accessible without testing
โ Do: Test connectivity before running operations
# Test connectivity
curl -v https://appflowy.ark-node.com/api/workspace
# Test DNS resolution
nslookup appflowy.ark-node.com
**Context:** Agent needs to track its work in AppFlowy for team visibility.
#!/usr/bin/env python3
from appflowy_client import AppFlowyClient
def track_agent_task(task_description, status="In Progress"):
"""Create or update task for agent work."""
client = AppFlowyClient()
task_info = {
'title': task_description,
'status': status,
'assignee': 'AI Agent',
'priority': 'Medium',
'tags': ['automated', 'agent-work']
}
result = client.create_row(
workspace_id=client.workspace_id,
database_id=os.getenv('APPFLOWY_TODOS_DB_ID'),
data=task_info
)
print(f"โ
Task tracked: {result['id']}")
return result['id']
# Usage
task_id = track_agent_task("Implementing AppFlowy integration skill")
See workflows/task-management.md for complete patterns.
def generate_standup_summary(client, database_id):
"""Generate daily standup summary from AppFlowy tasks."""
from datetime import datetime, timedelta
# Get tasks updated in last 24 hours
yesterday = (datetime.utcnow() - timedelta(days=1)).isoformat() + 'Z'
updated_rows = client.get_updated_rows(client.workspace_id, database_id, yesterday)
# ... organize by status and format output ...
return formatted_summary
# Usage
standup = generate_standup_summary(client, database_id)
print(standup)
See workflows/task-management.md for complete implementation.
def generate_project_dashboard(client, database_id):
"""Create comprehensive project status dashboard."""
# Get all tasks
rows = client.get_database_rows(client.workspace_id, database_id)
# Analyze status, priority, assignee workload
# ... (see workflows/task-management.md for full code) ...
return dashboard_output
See workflows/task-management.md for complete implementation.
Scenario 1: Using a configuration file
# appflowy-sync.yaml
parent_page: "My Project Docs"
structure:
- folder: "Getting Started"
documents:
- source: "README.md"
name: "Overview"
- source: "docs/quickstart.md"
name: "Quick Start"
- folder: "API Reference"
documents:
- source: "docs/api/**/*.md" # Glob pattern
- folder: "Examples"
documents:
- source: "examples/*/README.md"
name_from_path: true # Use parent folder name
# Sync with config
python sync_project.py --config appflowy-sync.yaml
# Dry run first to preview
python sync_project.py --config appflowy-sync.yaml --dry-run
# Force re-sync all files
python sync_project.py --config appflowy-sync.yaml --force
Scenario 2: Auto-discovery mode (no config needed)
# Automatically discover and sync all documentation
python sync_project.py --auto-discover --parent "Documentation"
# Auto-discover with dry run
python sync_project.py --auto-discover --parent "Docs" --dry-run
Scenario 3: Sync specific folder
# Sync only the docs/ folder
python sync_project.py --source docs/ --parent "API Docs"
# Sync with custom project root
python sync_project.py --source docs/ --parent "Docs" --project-root /path/to/project
Scenario 4: Use with custom .env file
# For projects outside the default credential location
python sync_project.py \
--config appflowy-sync.yaml \
--env-file /path/to/project/.env
Integration with CI/CD:
# .github/workflows/sync-docs.yml
name: Sync Documentation to AppFlowy
on:
push:
branches: [main]
paths: ['docs/**', 'README.md']
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: pip install requests pyyaml
- name: Sync to AppFlowy
env:
APPFLOWY_API_URL: ${{ secrets.APPFLOWY_API_URL }}
APPFLOWY_API_TOKEN: ${{ secrets.APPFLOWY_API_TOKEN }}
APPFLOWY_WORKSPACE_ID: ${{ secrets.APPFLOWY_WORKSPACE_ID }}
run: |
python sync_project.py --config appflowy-sync.yaml
Benefits:
<related_skills> This skill works well with:
<integration_notes> Working with Other Tools:
Zapier Integration: AppFlowy supports Zapier, enabling no-code automation between AppFlowy and 5,000+ apps.
GitHub Integration: Combine with GitHub Actions to auto-create AppFlowy tasks from issues or PRs.
Skill Composition:
<reference_guides> Documentation:
workflows/sync-documentation.md - Sync AI_agents docs to AppFlowyworkflows/sync-tasks.md - Sync AI_agents tasks to Kanban boardworkflows/git-sync.md - Automated sync with git hooks and cronworkflows/task-management.md - Creating, updating, and tracking tasksworkflows/workspace-operations.md - Workspace and database managementworkflows/server-deployment.md - Server setup and operationsworkflows/troubleshooting.md - Common issues and solutionsreferences/api-reference.md - Complete API endpoint documentationreferences/setup_guide.md - Deployment and configuration guideSync Scripts:
scripts/sync_project.py - Generic sync for any project (config-driven, YAML/JSON config)scripts/sync_docs.py - AI_agents documentation sync (hardcoded mappings)scripts/sync_tasks.py - AI_agents task sync from multiple data sourcesappflowy-sync.example.yaml - Example configuration for generic syncGeneric Sync Features:
The sync_project.py script is designed to work with ANY project:
docs/**/*.md)Other Scripts:
scripts/appflowy_client.py - Python client libraryscripts/task_tracker.py - Task tracking utilitiesscripts/workspace_setup.py - Workspace initializationscripts/manage_server.sh - Server management scriptExternal Resources:
<version_history> Version 2.4.0 (2025-12-08)
appflowy-mapping.yaml) for explicit page IDsVersion 2.3.0 (2025-12-08)
sync_project.py)docs/**/*.md)appflowy-sync.example.yaml with comprehensive examplesVersion 2.2.0 (2025-12-08)
Version 2.1.0 (2025-12-08)
Version 2.0.0 (2025-12-04)
Version 1.0.0 (2025-11-22)