{
  "schemaVersion": "1.0",
  "item": {
    "slug": "evc-team-relay",
    "name": "EVC Team Relay",
    "source": "tencent",
    "type": "skill",
    "category": "内容创作",
    "sourceUrl": "https://clawhub.ai/venturecrew/evc-team-relay",
    "canonicalUrl": "https://clawhub.ai/venturecrew/evc-team-relay",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/evc-team-relay",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=evc-team-relay",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "scripts/upsert-file.sh",
      "scripts/read-file.sh",
      "scripts/read.sh",
      "scripts/create-file.sh"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/evc-team-relay"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/evc-team-relay",
    "agentPageUrl": "https://openagent3.xyz/skills/evc-team-relay/agent",
    "manifestUrl": "https://openagent3.xyz/skills/evc-team-relay/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/evc-team-relay/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "EVC Team Relay",
        "body": "REST API skill for reading and writing collaborative Obsidian vault documents via EVC Team Relay."
      },
      {
        "title": "Environment variables",
        "body": "VariableRequiredDescriptionRELAY_CP_URLyesControl plane URL, e.g. https://cp.tr.entire.vcRELAY_EMAILyesUser email for authenticationRELAY_PASSWORDyesUser passwordRELAY_TOKENnoJWT token (set via export RELAY_TOKEN=$(scripts/auth.sh))"
      },
      {
        "title": "Quick start",
        "body": "# 1. Authenticate — get a JWT token (stored in env var, not visible in ps)\nexport RELAY_TOKEN=$(scripts/auth.sh)\n\n# 2. List shares to find available documents\nscripts/list-shares.sh\n\n# 3. Read a file from a folder share BY PATH (most common)\nscripts/read-file.sh <folder_share_id> \"Marketing/plan.md\"\n\n# 4. Create or update a file in a folder share\nscripts/upsert-file.sh <folder_share_id> \"note.md\" \"# Content\"\n\n# 5. List all files in a folder share\nscripts/list-files.sh <folder_share_id>\n\n# 6. Delete a file from a folder share\nscripts/delete-file.sh <folder_share_id> \"old-note.md\"\n\n# 7. Read a doc share (single document, share_id = doc_id)\nscripts/read.sh <share_id>\n\n# 8. Write to a doc share\nscripts/write.sh <share_id> <share_id> \"# Updated content\"\n\nAll scripts accept the token via RELAY_TOKEN env var (preferred) or as the first CLI argument (backward-compatible)."
      },
      {
        "title": "Two kinds of shares",
        "body": "Doc shareFolder shareContainsSingle documentMultiple filesdoc_idSame as share_idEach file has its own doc_id (in folder metadata)Readread.sh <share_id>read-file.sh <share_id> \"path/to/file.md\"Writewrite.sh <share_id> <share_id> <content>upsert-file.sh <share_id> \"path\" <content>DeleteN/Adelete-file.sh <share_id> \"path\"\n\nMost shares are folder shares. Use read-file.sh and upsert-file.sh — they handle path resolution automatically.\n\nWarning: write.sh does NOT work for folder shares — it writes content but does not register the file in folder metadata, so Obsidian will never see it. The script detects folder shares and refuses with an error."
      },
      {
        "title": "Scripts reference",
        "body": "ScriptPurposeArgsauth.shGet JWT token—list-shares.shList all shares[kind] [owned_only]list-files.shList files in folder share<share_id>read-file.shRead file by path (folder share)<share_id> <file_path>read.shRead by doc_id (low-level)<share_id> [doc_id]upsert-file.shCreate/update file (folder share)<share_id> <file_path> <content>write.shWrite by doc_id (doc shares only)<share_id> <doc_id> <content>delete-file.shDelete file from folder share<share_id> <file_path>create-file.shCreate new file (low-level)<share_id> <file_path> <content>\n\nBold = recommended for most use cases. All scripts use RELAY_TOKEN env var (or accept token as first arg)."
      },
      {
        "title": "Authentication",
        "body": "All API calls require a Bearer JWT token. Get one via login:\n\ncurl -s -X POST \"$RELAY_CP_URL/v1/auth/login\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\": \"'$RELAY_EMAIL'\", \"password\": \"'$RELAY_PASSWORD'\"}' \\\n  | jq -r '.access_token'\n\nResponse:\n\n{\n  \"access_token\": \"eyJ...\",\n  \"refresh_token\": \"...\",\n  \"token_type\": \"bearer\",\n  \"expires_in\": 3600\n}\n\nUse the access_token as Authorization: Bearer <token> header on all subsequent requests.\n\nWhen the token expires (1 hour), refresh it:\n\ncurl -s -X POST \"$RELAY_CP_URL/v1/auth/refresh\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"refresh_token\": \"'$REFRESH_TOKEN'\"}'"
      },
      {
        "title": "Listing shares",
        "body": "Shares are the access units — each share maps to a document or folder in the Obsidian vault.\n\ncurl -s \"$RELAY_CP_URL/v1/shares\" \\\n  -H \"Authorization: Bearer $TOKEN\" | jq\n\nResponse (array):\n\n[\n  {\n    \"id\": \"a1b2c3d4-...\",\n    \"kind\": \"doc\",\n    \"path\": \"Projects/meeting-notes.md\",\n    \"visibility\": \"private\",\n    \"is_owner\": true,\n    \"user_role\": null,\n    \"web_published\": false\n  },\n  {\n    \"id\": \"e5f6g7h8-...\",\n    \"kind\": \"folder\",\n    \"path\": \"Projects/\",\n    \"visibility\": \"private\",\n    \"is_owner\": false,\n    \"user_role\": \"editor\"\n  }\n]\n\nKey fields:\n\nid — share UUID, used as share_id in all operations\nkind — doc (single file) or folder (directory)\npath — Obsidian vault-relative path\nuser_role — viewer (read-only), editor (read-write), or null (owner)\n\nFilter options: ?kind=doc, ?owned_only=true, ?member_only=true, ?skip=0&limit=50."
      },
      {
        "title": "Listing files in a folder share",
        "body": "scripts/list-files.sh <share_id>\n\nResponse:\n\n{\n  \"doc_id\": \"e5f6g7h8-...\",\n  \"files\": {\n    \"meeting-notes.md\": {\"doc_id\": \"abc123-...\", \"type\": \"markdown\"},\n    \"project-plan.md\": {\"doc_id\": \"def456-...\", \"type\": \"markdown\"}\n  }\n}\n\nEach key is the file's path within the folder. The doc_id field is the document identifier used for content operations. The share_id for content requests is always the folder share's ID.\n\nNote: The API response uses id as the field name. This is the same as doc_id — use it wherever doc_id is needed."
      },
      {
        "title": "By path (recommended for folder shares)",
        "body": "scripts/read-file.sh <folder_share_id> \"Marketing/plan.md\"\n\nThis resolves the path to a doc_id internally and returns:\n\n{\n  \"doc_id\": \"abc123-...\",\n  \"content\": \"# Marketing Plan\\n\\nContent here...\",\n  \"format\": \"text\",\n  \"path\": \"Marketing/plan.md\"\n}"
      },
      {
        "title": "By doc_id (low-level)",
        "body": "scripts/read.sh <share_id> [doc_id] [key]\n\nFor doc shares, omit doc_id (defaults to share_id). For folder shares, pass the file's doc_id from list-files.sh."
      },
      {
        "title": "Folder shares — use upsert-file.sh",
        "body": "# Create or update — auto-detects which operation is needed\nscripts/upsert-file.sh <folder_share_id> \"note.md\" \"# Updated content\"\n\n# Pipe content from stdin\necho \"# Content\" | scripts/upsert-file.sh <folder_share_id> \"note.md\" -\n\nResponse includes an operation field: \"created\" or \"updated\"."
      },
      {
        "title": "Doc shares — use write.sh",
        "body": "scripts/write.sh <share_id> <share_id> \"# Updated Notes\"\n\nwrite.sh refuses folder shares — if you accidentally pass a folder share_id as doc_id, it detects this and exits with an error directing you to upsert-file.sh."
      },
      {
        "title": "Read a specific note by path (most common)",
        "body": "# If you know the folder share_id:\nscripts/read-file.sh <folder_share_id> \"Marketing/docs/plan.md\"\n\n# If you need to find the share first:\nscripts/list-shares.sh  # find the folder share\nscripts/read-file.sh <share_id> \"path/to/file.md\""
      },
      {
        "title": "Create or update a file",
        "body": "# Always works, whether the file exists or not\nscripts/upsert-file.sh <folder_share_id> \"note.md\" \"# Content\""
      },
      {
        "title": "Delete a file",
        "body": "scripts/delete-file.sh <folder_share_id> \"old-note.md\""
      },
      {
        "title": "Error codes",
        "body": "StatusMeaning400Invalid share_id format401Missing or expired token — re-authenticate403Insufficient permissions (viewer trying to write, or non-member)404Share or file not found (check path spelling, use list-files.sh to verify)422Missing required field (share_id, content)502Relay server unavailable — retry later"
      },
      {
        "title": "Terminology",
        "body": "TermMeaningshare_idUUID of a share (doc or folder). Used for ACL checks in all requests.doc_idUUID of an individual document. For doc shares, equals share_id. For folder shares, each file has its own doc_id.idSame as doc_id — the API response field name. Use interchangeably.file_pathRelative path within a folder share (e.g. \"Marketing/plan.md\")."
      },
      {
        "title": "References",
        "body": "references/api.md — full API reference with all endpoints"
      }
    ],
    "body": "EVC Team Relay\n\nREST API skill for reading and writing collaborative Obsidian vault documents via EVC Team Relay.\n\nEnvironment variables\nVariable\tRequired\tDescription\nRELAY_CP_URL\tyes\tControl plane URL, e.g. https://cp.tr.entire.vc\nRELAY_EMAIL\tyes\tUser email for authentication\nRELAY_PASSWORD\tyes\tUser password\nRELAY_TOKEN\tno\tJWT token (set via export RELAY_TOKEN=$(scripts/auth.sh))\nQuick start\n# 1. Authenticate — get a JWT token (stored in env var, not visible in ps)\nexport RELAY_TOKEN=$(scripts/auth.sh)\n\n# 2. List shares to find available documents\nscripts/list-shares.sh\n\n# 3. Read a file from a folder share BY PATH (most common)\nscripts/read-file.sh <folder_share_id> \"Marketing/plan.md\"\n\n# 4. Create or update a file in a folder share\nscripts/upsert-file.sh <folder_share_id> \"note.md\" \"# Content\"\n\n# 5. List all files in a folder share\nscripts/list-files.sh <folder_share_id>\n\n# 6. Delete a file from a folder share\nscripts/delete-file.sh <folder_share_id> \"old-note.md\"\n\n# 7. Read a doc share (single document, share_id = doc_id)\nscripts/read.sh <share_id>\n\n# 8. Write to a doc share\nscripts/write.sh <share_id> <share_id> \"# Updated content\"\n\n\nAll scripts accept the token via RELAY_TOKEN env var (preferred) or as the first CLI argument (backward-compatible).\n\nTwo kinds of shares\n\tDoc share\tFolder share\nContains\tSingle document\tMultiple files\ndoc_id\tSame as share_id\tEach file has its own doc_id (in folder metadata)\nRead\tread.sh <share_id>\tread-file.sh <share_id> \"path/to/file.md\"\nWrite\twrite.sh <share_id> <share_id> <content>\tupsert-file.sh <share_id> \"path\" <content>\nDelete\tN/A\tdelete-file.sh <share_id> \"path\"\n\nMost shares are folder shares. Use read-file.sh and upsert-file.sh — they handle path resolution automatically.\n\nWarning: write.sh does NOT work for folder shares — it writes content but does not register the file in folder metadata, so Obsidian will never see it. The script detects folder shares and refuses with an error.\n\nScripts reference\nScript\tPurpose\tArgs\nauth.sh\tGet JWT token\t—\nlist-shares.sh\tList all shares\t[kind] [owned_only]\nlist-files.sh\tList files in folder share\t<share_id>\nread-file.sh\tRead file by path (folder share)\t<share_id> <file_path>\nread.sh\tRead by doc_id (low-level)\t<share_id> [doc_id]\nupsert-file.sh\tCreate/update file (folder share)\t<share_id> <file_path> <content>\nwrite.sh\tWrite by doc_id (doc shares only)\t<share_id> <doc_id> <content>\ndelete-file.sh\tDelete file from folder share\t<share_id> <file_path>\ncreate-file.sh\tCreate new file (low-level)\t<share_id> <file_path> <content>\n\nBold = recommended for most use cases. All scripts use RELAY_TOKEN env var (or accept token as first arg).\n\nAuthentication\n\nAll API calls require a Bearer JWT token. Get one via login:\n\ncurl -s -X POST \"$RELAY_CP_URL/v1/auth/login\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\": \"'$RELAY_EMAIL'\", \"password\": \"'$RELAY_PASSWORD'\"}' \\\n  | jq -r '.access_token'\n\n\nResponse:\n\n{\n  \"access_token\": \"eyJ...\",\n  \"refresh_token\": \"...\",\n  \"token_type\": \"bearer\",\n  \"expires_in\": 3600\n}\n\n\nUse the access_token as Authorization: Bearer <token> header on all subsequent requests.\n\nWhen the token expires (1 hour), refresh it:\n\ncurl -s -X POST \"$RELAY_CP_URL/v1/auth/refresh\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"refresh_token\": \"'$REFRESH_TOKEN'\"}'\n\nListing shares\n\nShares are the access units — each share maps to a document or folder in the Obsidian vault.\n\ncurl -s \"$RELAY_CP_URL/v1/shares\" \\\n  -H \"Authorization: Bearer $TOKEN\" | jq\n\n\nResponse (array):\n\n[\n  {\n    \"id\": \"a1b2c3d4-...\",\n    \"kind\": \"doc\",\n    \"path\": \"Projects/meeting-notes.md\",\n    \"visibility\": \"private\",\n    \"is_owner\": true,\n    \"user_role\": null,\n    \"web_published\": false\n  },\n  {\n    \"id\": \"e5f6g7h8-...\",\n    \"kind\": \"folder\",\n    \"path\": \"Projects/\",\n    \"visibility\": \"private\",\n    \"is_owner\": false,\n    \"user_role\": \"editor\"\n  }\n]\n\n\nKey fields:\n\nid — share UUID, used as share_id in all operations\nkind — doc (single file) or folder (directory)\npath — Obsidian vault-relative path\nuser_role — viewer (read-only), editor (read-write), or null (owner)\n\nFilter options: ?kind=doc, ?owned_only=true, ?member_only=true, ?skip=0&limit=50.\n\nListing files in a folder share\nscripts/list-files.sh <share_id>\n\n\nResponse:\n\n{\n  \"doc_id\": \"e5f6g7h8-...\",\n  \"files\": {\n    \"meeting-notes.md\": {\"doc_id\": \"abc123-...\", \"type\": \"markdown\"},\n    \"project-plan.md\": {\"doc_id\": \"def456-...\", \"type\": \"markdown\"}\n  }\n}\n\n\nEach key is the file's path within the folder. The doc_id field is the document identifier used for content operations. The share_id for content requests is always the folder share's ID.\n\nNote: The API response uses id as the field name. This is the same as doc_id — use it wherever doc_id is needed.\n\nReading files\nBy path (recommended for folder shares)\nscripts/read-file.sh <folder_share_id> \"Marketing/plan.md\"\n\n\nThis resolves the path to a doc_id internally and returns:\n\n{\n  \"doc_id\": \"abc123-...\",\n  \"content\": \"# Marketing Plan\\n\\nContent here...\",\n  \"format\": \"text\",\n  \"path\": \"Marketing/plan.md\"\n}\n\nBy doc_id (low-level)\nscripts/read.sh <share_id> [doc_id] [key]\n\n\nFor doc shares, omit doc_id (defaults to share_id). For folder shares, pass the file's doc_id from list-files.sh.\n\nWriting files\nFolder shares — use upsert-file.sh\n# Create or update — auto-detects which operation is needed\nscripts/upsert-file.sh <folder_share_id> \"note.md\" \"# Updated content\"\n\n# Pipe content from stdin\necho \"# Content\" | scripts/upsert-file.sh <folder_share_id> \"note.md\" -\n\n\nResponse includes an operation field: \"created\" or \"updated\".\n\nDoc shares — use write.sh\nscripts/write.sh <share_id> <share_id> \"# Updated Notes\"\n\n\nwrite.sh refuses folder shares — if you accidentally pass a folder share_id as doc_id, it detects this and exits with an error directing you to upsert-file.sh.\n\nCommon workflows\nRead a specific note by path (most common)\n# If you know the folder share_id:\nscripts/read-file.sh <folder_share_id> \"Marketing/docs/plan.md\"\n\n# If you need to find the share first:\nscripts/list-shares.sh  # find the folder share\nscripts/read-file.sh <share_id> \"path/to/file.md\"\n\nCreate or update a file\n# Always works, whether the file exists or not\nscripts/upsert-file.sh <folder_share_id> \"note.md\" \"# Content\"\n\nDelete a file\nscripts/delete-file.sh <folder_share_id> \"old-note.md\"\n\nError codes\nStatus\tMeaning\n400\tInvalid share_id format\n401\tMissing or expired token — re-authenticate\n403\tInsufficient permissions (viewer trying to write, or non-member)\n404\tShare or file not found (check path spelling, use list-files.sh to verify)\n422\tMissing required field (share_id, content)\n502\tRelay server unavailable — retry later\nTerminology\nTerm\tMeaning\nshare_id\tUUID of a share (doc or folder). Used for ACL checks in all requests.\ndoc_id\tUUID of an individual document. For doc shares, equals share_id. For folder shares, each file has its own doc_id.\nid\tSame as doc_id — the API response field name. Use interchangeably.\nfile_path\tRelative path within a folder share (e.g. \"Marketing/plan.md\").\nReferences\nreferences/api.md — full API reference with all endpoints"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/venturecrew/evc-team-relay",
    "publisherUrl": "https://clawhub.ai/venturecrew/evc-team-relay",
    "owner": "venturecrew",
    "version": "1.1.2",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/evc-team-relay",
    "downloadUrl": "https://openagent3.xyz/downloads/evc-team-relay",
    "agentUrl": "https://openagent3.xyz/skills/evc-team-relay/agent",
    "manifestUrl": "https://openagent3.xyz/skills/evc-team-relay/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/evc-team-relay/agent.md"
  }
}