{"id":50493807,"url":"https://github.com/nowhitestar/meti","last_synced_at":"2026-06-02T05:03:33.942Z","repository":{"id":356274844,"uuid":"1229538502","full_name":"Nowhitestar/Meti","owner":"Nowhitestar","description":"One manifest, every Chinese-platform you publish to. Drafts on WeChat OA · Xiaohongshu · X Articles · Substack · WeChat 贴图 from a single YAML.","archived":false,"fork":false,"pushed_at":"2026-05-26T03:58:26.000Z","size":604,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T05:27:10.255Z","etag":null,"topics":["automation","claude-code","content-publishing","draft-first","manifest-driven","openclaw","publishing","python","substack","wechat","x-articles","xiaohongshu"],"latest_commit_sha":null,"homepage":"https://liao.uno/meti/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nowhitestar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-05T06:29:25.000Z","updated_at":"2026-05-26T03:58:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Nowhitestar/Meti","commit_stats":null,"previous_names":["nowhitestar/meti"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/Nowhitestar/Meti","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nowhitestar%2FMeti","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nowhitestar%2FMeti/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nowhitestar%2FMeti/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nowhitestar%2FMeti/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nowhitestar","download_url":"https://codeload.github.com/Nowhitestar/Meti/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nowhitestar%2FMeti/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33806997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","claude-code","content-publishing","draft-first","manifest-driven","openclaw","publishing","python","substack","wechat","x-articles","xiaohongshu"],"created_at":"2026-06-02T05:03:30.006Z","updated_at":"2026-06-02T05:03:33.927Z","avatar_url":"https://github.com/Nowhitestar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.svg\" width=\"72\" height=\"72\" alt=\"Meti\"/\u003e\n  \u003ch1\u003eMeti\u003c/h1\u003e\n  \u003cp\u003e\u003cb\u003eOne manifest, every Chinese-platform you publish to.\u003c/b\u003e\u003c/p\u003e\n  \u003ca href=\"https://github.com/Nowhitestar/meti/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/Nowhitestar/meti?style=flat-square\" alt=\"Stars\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/Nowhitestar/meti/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/tag/Nowhitestar/meti?label=version\u0026style=flat-square\" alt=\"Version\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/Nowhitestar/meti/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/Nowhitestar/meti/ci.yml?branch=main\u0026style=flat-square\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.python.org/downloads/\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.10+-blue?style=flat-square\" alt=\"Python 3.10+\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n## Why\n\nMeti (μῆτις, *mētis* — Greek for \"wise counsel\"; *meticulous* in English; 媒体 *méi-tǐ* — \"media\" in Mandarin). Three readings, one idea: **publishing should be careful, deliberate, and reproducible — not a tab-juggling marathon.**\n\nWriters who care about more than one Chinese-platform audience face the same chore: open WeChat OA, paste, save draft. Open Xiaohongshu, paste, save draft. Open X, paste, save. Open Substack, paste, save. Each platform forgets what the other knows. Each tab is a place a typo can hide. Each retry costs the same five minutes.\n\nMeti collapses that into **one YAML manifest → drafts on every platform**, with an explicit safety model:\n\n- **Draft-first by default.** Public publishing requires explicit opt-in *plus* an in-conversation confirmation. Mistakes stop at the draft folder.\n- **Cookies stay in your real Chrome.** No CDP debug-port dance, no fresh-Chromium login dance. Browser-flow providers reuse your existing logged-in session via the [OpenCLI Bridge](https://github.com/jackwener/opencli) extension.\n- **Credentials are encrypted at rest.** `age`-encrypted vault at `~/.config/meti/credentials.json.age`. Secrets never appear in run artifacts.\n- **Every run is reproducible.** A self-contained run dir captures the locked manifest, payloads, checkpoints, log, and result. Resume from any failure point with `meti resume \u003crun-dir\u003e`.\n\nWorks as a [Claude Code](https://claude.com/claude-code) plugin **and** as an [OpenClaw](https://openclaw.com) skill from the same source — say what you want in natural language, and the wizard walks you through source extraction → target selection → manifest assembly → draft.\n\n## See it\n\n| Provider | Drafts to | How it gets there |\n|---|---|---|\n| `wechat-article` | 公众号 图文 (article) | WeChat Open Platform API — `material/add_material` + `draft/add` |\n| `wechat-image` | 公众号 贴图 (image post) | OpenCLI Bridge → real Chrome → `DataTransfer` injection |\n| `xiaohongshu` | 小红书 草稿 (note) | OpenCLI Bridge → real Chrome → Creator Studio |\n| `x-article` | X Articles (Premium) | OpenCLI Bridge → real Chrome |\n| `x-thread` | X thread composer | OpenCLI Bridge → real Chrome, stops before `Post all` |\n| `substack` | Substack post draft | OpenCLI Bridge → real Chrome |\n\nAll browser-flow providers reuse your logged-in Chrome session; Meti does not ask you to capture raw cookies for them. See [docs/browser-connectors.md](docs/browser-connectors.md).\n\n## Install\n\n**As a Claude Code local plugin** (current recommended path)\n\n```bash\ngit clone https://github.com/Nowhitestar/meti.git\n# Claude Code: settings → plugins → load from directory\n```\n\n**As a Claude Code marketplace plugin** (future path)\n\nThe Claude Code marketplace submission is pending. Once Meti is listed, the install becomes:\n\n```\n/plugin install meti\n```\n\n**As an OpenClaw skill**\n\n```bash\ngit clone https://github.com/Nowhitestar/meti.git ~/.openclaw/skills/meti\n```\n\n**Versioned release install / update**\n\n```bash\n# latest stable from GitHub Releases\nscripts/install.sh --latest --target ~/.openclaw/skills/meti\n\n# pinned install or rollback\nscripts/install.sh --version vX.Y.Z --target ~/.openclaw/skills/meti --yes\n\n# from an existing checkout/install\nmeti update --latest\nmeti update --version vX.Y.Z\n```\n\nNormal reinstall/update preserves `~/.config/meti`,\n`~/.config/meti/credentials.json.age`, and `~/.config/meti/age-key.txt`.\n\n**Direct CLI** (Python ≥ 3.10)\n\n```bash\npython3 -m venv .venv\n.venv/bin/python -m pip install -e \".[dev]\"\n.venv/bin/meti --help\n```\n\nThe editable dev install includes runtime dependencies such as `pyrage` and\n`tomli_w`. Using a venv avoids Homebrew Python's PEP 668\nexternally-managed-environment failure; use global pip only in environments\nwhere global installs are explicitly allowed.\n\n**Optional: OpenCLI Bridge** for `wechat-image`, `xiaohongshu`, `x-article`, `x-thread`, and `substack`. One-time setup:\n\n```bash\nbrew install node            # or apt install nodejs npm — needs Node ≥ 21\n# Install Chrome extension: https://chromewebstore.google.com/detail/opencli/ildkmabpimmkaediidaifkhjpohdnifk\nmeti browser status          # → OK Browser Bridge connected\n```\n\nFull setup: [docs/browser-connectors.md](docs/browser-connectors.md).\n\nDistribution, clean install, upgrade, and pre-release checks are documented in\n[docs/distribution.md](docs/distribution.md). The automated release gate is\ndraft-safe and account-free by default:\n\n```bash\npython scripts/check_release.py\n```\n\n## Quickstart\n\n**The conversational wizard** (in Claude Code or OpenClaw):\n\n\u003e 帮我把这篇文章发到公众号、X 长文、Substack 草稿。\n\nThe wizard reads `core/wizard/*.md` and walks you through extraction, target selection, manifest assembly, and draft execution — no manifest YAML to hand-write.\n\n**The CLI** (when you already have a manifest):\n\n```bash\n# Validate without executing\nmeti validate examples/longform.yaml\n\n# Configure credentials for a provider\nmeti setup wechat-article\n\n# Publish (defaults to draft mode in the manifest)\nmeti publish examples/longform.yaml\n\n# Resume from where the last run failed\nmeti resume runs/20260507-001255-mmp\n\n# Inspect state\nmeti list providers\nmeti providers list\nmeti list accounts\nmeti list runs\nmeti doctor\n```\n\nAfter `publish` or `resume`, inspect `runs/\u003crun-id\u003e/result.json` for the\nschema-v2 run contract: top-level `status`, `next_action`, `resume_targets`,\n`review_targets`, and per-target `next_action`. See\n[docs/run-results.md](docs/run-results.md).\n\nA minimal manifest:\n\n```yaml\nschema_version: \"0.2\"\ntype: longform\ntitle: \"AI for the rest of us\"\nbody: ./article.md\nmode: draft\nlanguage: zh-CN\ntargets:\n  - wechat-article\n  - x-article\n  - substack\nassets:\n  cover: ./cover.png\ntags: [ai, essay]\n```\n\n## Design\n\n**One language, every constraint encoded.** Meti's manifest is a YAML version of \"what should land on every platform\" — title length caps, tag count limits, image-format constraints all live in `providers/*/rules.py` and run before any network call. A 64-character WeChat title and a 280-character XHS title are both rejected at validate-time, not at the platform.\n\n**Provider abstraction is small on purpose.** Five methods (`validate`, `prepare`, `execute`, `health_check`, plus a registration block). New bundled platforms drop into `providers/\u003cname\u003e/`; user providers live under `~/.config/meti/providers/\u003cname\u003e/` and require explicit `meti providers trust \u003cname\u003e` before their Python is imported. See [docs/provider-contract.md](docs/provider-contract.md), [docs/provider-api-template.md](docs/provider-api-template.md), and [docs/provider-browser-template.md](docs/provider-browser-template.md).\n\n**Two execute paths per platform:**\n\n| Path | When | Trade-off |\n|---|---|---|\n| **API** (`wechat-article`) | Platform exposes a draft API + you have AppID/Secret | Fast, scriptable, no Chrome dependency |\n| **Browser-flow** (`wechat-image`, `xiaohongshu`, `x-article`, `x-thread`, `substack`) | No API exists, OR API can't create the post type | Reuses real Chrome session, works inside the browser the platform expects, breaks when platform UI drifts (selectors are constants at the top of each `internal/browser_flow.py`) |\n\n**Safety is a property of the design, not a runtime check.** `mode: draft` is the default for every provider. Bundled providers currently advertise `publish: false`; reopening public publish support would require explicit future provider work plus an active confirmation gate. Vault writes are atomic (tmp + fsync + os.replace) under flock — no concurrent-write data loss. Run dirs are append-only — `result.json` is written once, at the end.\n\nFull architecture: [docs/architecture.md](docs/architecture.md). Safety policy: [docs/safety-policy.md](docs/safety-policy.md). Browser connector internals: [docs/browser-connectors.md](docs/browser-connectors.md).\n\n## Project layout\n\n```\ncore/                  # host-agnostic Python (manifest, providers, vault, runs)\nproviders/             # bundled first-party providers\n  wechat_article/      # API\n  wechat_image/        # OpenCLI Bridge (贴图)\n  xiaohongshu/         # OpenCLI Bridge\n  x_article/           # OpenCLI Bridge\n  x_thread/            # OpenCLI Bridge\n  substack/            # OpenCLI Bridge\nscripts/meti.py        # CLI entry\n.claude-plugin/        # Claude Code plugin manifest\nSKILL.md               # OpenClaw + Claude Code skill manifest\ndocs/                  # user-facing docs\ntests/                 # 142 unit + integration tests\n```\n\n## Roadmap\n\n- ✅ **v0.2** — Provider abstraction + dual-host distribution + wizard + age-encrypted vault\n- ✅ **v0.3** — WeChat API proxy (split-routing IP whitelist) + vault hardening + `meti resume`\n- ✅ **v0.3.1** — `x-article` + `substack` connectors via OpenCLI Bridge\n- ✅ **v0.3.2** — `wechat-image` (贴图) connector — solves the local-file-upload + request-signing field problem\n- ✅ **v0.4** — Rebrand to Meti\n- ✅ **v0.4.x** — `xiaohongshu` and `x-thread` browser-flow draft paths\n- 🔒 **v0.4.x** — Marketplace and distribution readiness: version sync, release gate, clean install docs, submission packet\n- 💤 **Deferred** — `wechat-channel` (视频号) connector\n- 💤 **Deferred** — Multi-account routing (`target.account: \u003cname\u003e`) + per-provider session-expiry detection\n\n## Contributing\n\nBug reports, feature requests, and provider PRs are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the dev environment, test conventions, and provider authoring guide.\n\nThe fastest way to add a new platform: copy [`providers/substack/`](providers/substack/) (smallest browser-flow provider), update the URL pattern + selectors, register in the manifest schema. Real-account verification is mandatory before merge — see [docs/manual-verification.md](docs/manual-verification.md).\n\n## License\n\n[MIT](LICENSE) © 2026 Lewis Liao\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnowhitestar%2Fmeti","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnowhitestar%2Fmeti","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnowhitestar%2Fmeti/lists"}