From agent-skills
Sync Obsidian artifact files (problems.md, plan.md) to a Wrike kanban board. Detects changes via Obsidian sync history, creates/updates/resolves Wrike tasks. Designed for hourly scheduled invocation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/agent-skills:wrike-syncThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Sync problems.md and plan.md artifacts from an Obsidian vault to a Wrike project board. Designed to run cheaply and autonomously - exit as early as possible when there's nothing to do.
Sync problems.md and plan.md artifacts from an Obsidian vault to a Wrike project board. Designed to run cheaply and autonomously - exit as early as possible when there's nothing to do.
All configuration is read from a local config file, NOT hardcoded in this skill. The invoker must provide the config file path as an argument, or the skill looks for it at a default location specified in the invocation prompt.
The config file is JSON with this structure:
{
"config": {
"obsidian_vault": "<vault name>",
"obsidian_cli": "<full path to obsidian CLI executable, e.g. C:\\Users\\you\\AppData\\Local\\Programs\\Obsidian\\Obsidian.com>",
"wrike_project_id": "<project ID>",
"wrike_space_id": "<space ID>",
"default_assignee": "<contact ID>",
"owner_initials": "<2-3 char initials, e.g. TC>",
"custom_fields": {
"feature_area": "<field ID>",
"type": "<field ID>"
},
"statuses": {
"not_started": "<status ID>",
"in_progress": "<status ID>",
"blocked": "<status ID>",
"completed": "<status ID>",
"on_hold": "<status ID>",
"cancelled": "<status ID>"
},
"tracked_files": [
{
"feature_area": "<Feature Area value>",
"feature_prefix": "<2-3 char prefix, e.g. RC>",
"problems": "<vault-relative path to problems.md>",
"plan": "<vault-relative path to plan.md>",
"log": "<vault-relative path to log.md>"
}
]
},
"last_sync": null,
"files": {},
"task_map": {}
}
If the config file does not exist or is missing the config key, report the error and exit. Do not proceed without configuration.
Use the CLI path from config.obsidian_cli (fall back to bare obsidian if not set). All Obsidian CLI commands in this skill use this path.
Run:
"<config.obsidian_cli>" vault="<config.obsidian_vault>" sync:status
If this command fails (exit code != 0), Obsidian is not running. Log "Wrike sync skipped: Obsidian not running." and exit immediately.
Do NOT attempt any file reads or Wrike operations.
Read the config file. Extract config, last_sync, files, and task_map.
If last_sync is null, treat all tracked files as new (no previous sync).
For each entry in config.tracked_files, check both the problems and plan paths:
"<config.obsidian_cli>" vault="<config.obsidian_vault>" history path="<path>"
This returns output like:
<path>
1 2026-05-08 13:18 14.59 KB
2 2026-05-08 13:13 14.59 KB
3 2026-05-04 15:34 13.37 KB
Version 1 is always the most recent. Compare version 1's timestamp against the stored timestamp in files[path].last_synced_timestamp. If the timestamp is different (newer), the file changed.
If NO files changed across all tracked paths, exit immediately. No Wrike API calls needed. This is the common case and should cost minimal tokens.
If a file has no history (new file, never synced by Obsidian), treat it as changed.
For each changed file, read it using the Read tool. Parse based on file type:
Extract structured items from these sections:
Active items (items NOT under ## Resolved):
### P<N>: or ### P<N> - entries (problems/issues) - these are the primary sync targetsItems to SKIP (do not create Wrike tasks for these):
### R<N> entries (risks) - these are risk register items to watch, not work to do. They belong in the artifacts system for engineering context, not on a stakeholder kanban board.### Q<N> entries (questions/design decisions) - same reasoning. These get resolved through conversation, not through task completion.## Accepted Limitations, ## Technical Debt, ## Data Quality, or ## Lower Priority / Informational sections - these are context, not actionable work items for the board.For each active P-item, extract:
<feature_prefix>-<ID> (e.g., RC-P10, RI-P66)**Priority:** if presentResolved items (items under ## Resolved):
**Resolution:**Board-worthiness rule: Only P-items under ## Open Issues or ## Open Questions (when the question blocks visible work) belong on the board. If a P-item is filed under a context section (Tech Debt, Data Quality, Accepted Limitations, Informational), it stays in Obsidian only.
Extract items at the ### heading level (sprint/section headings).
For each ### heading:
<feature_prefix>-<normalized-heading> (lowercase, hyphens, truncate at 40 chars)## Active Work or referenced by ## Current State: In Progress## Future Phases: Not Started<ul><li> list. First and second level only. Truncate at 2000 chars.Standalone bullets outside sprint headings (e.g., under ### Quick Wins):
<feature_prefix>-<first-5-words-hyphenated>Headings to SKIP:
## Goal, ## Scope Context, ## Current State - structural## Key Decisions Outstanding - tracked via problems.md Q itemsUse wrike_search_tasks to fetch all tasks in the project:
folderId: <config.wrike_project_id>
pageSize: 200
fields: ["briefDescription", "customFields", "responsibleIds"]
descendants: true
Build a lookup map: check each task title for a [INITIALS:REF] tag (e.g., [TC:RC-P10]). Map ref -> Wrike task ID.
Also use task_map from state as a secondary lookup.
For each parsed item from Step 3:
Create a Wrike task:
<title> [<config.owner_initials>:<ref>] (e.g., User list not sorted [TC:RC-P21])<config.wrike_project_id><b>, <i>, <br/>, <ul>, <li>. Keep descriptions plain and clean.{"type": "Backlog"} - always use Backlog type. Do NOT set start, due, or duration. Never estimate effort."[\"<value>\"]"["<config.default_assignee>"]Record the Wrike task ID in task_map.
Update the Wrike task:
<br/><br/><b>Resolution:</b> <text>Only update if something material changed (priority, title, description content). Don't update for whitespace or formatting-only changes. Preserve the [INITIALS:ref] tag in the title.
Read the feature's log file (from tracked_files[].log in config). Search the most recent entries for a #### Completed Plan Items section containing matching heading text. If found:
If NOT found in the log, leave the task as-is. It may have been restructured.
Write the updated state file with:
config: preserved unchangedlast_sync: current ISO timestampfiles: updated timestamps (version 1 timestamp for each file)task_map: all ref -> Wrike task ID mappingsIf changes were made:
Wrike sync complete:
- Created: N tasks (list refs)
- Updated: N tasks (list refs)
- Completed: N tasks (list refs)
- Skipped: N items (internal-only)
When running as a routine, keep the report minimal.
config, report and exit.Optional arguments:
force - Skip change detection, re-sync all filesdry-run - Parse and diff but don't modify Wrike. Report what would change.<feature> - Only sync files for the named featurenpx claudepluginhub rexynexus/agent-skills --plugin agent-skillsCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.