deepseek-instagram 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ez4p1xEL
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,451 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # deepseek-instagram
4
+
5
+ **A resident Instagram assistant for DeepSeek Harness.**
6
+ It runs your account's Story / Note rhythm with a persona, a memory and your real DSH usage — and only *your* account can command it, through Instagram DMs.
7
+
8
+ [English](README.md) · [简体中文](README.zh-CN.md) · [繁體中文](README.zh-TW.md)
9
+
10
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
11
+ [![DSH](https://img.shields.io/badge/DSH-%E2%89%A5%200.1.7--rc.1-6c5ce7)](https://deepseek.com/harness)
12
+
13
+ <img src="https://raw.githubusercontent.com/Ez4p1xEL/deepseek-instagram/main/docs/images/story-card.png" width="300" alt="Daily DSH stats Story card" />
14
+ <img src="https://raw.githubusercontent.com/Ez4p1xEL/deepseek-instagram/main/docs/images/story-text.png" width="300" alt="Text Story card" />
15
+
16
+ <sub>Both cards are rendered locally at 1080×1920 by Pillow. The data above is demo data.</sub>
17
+
18
+ </div>
19
+
20
+ ---
21
+
22
+ **deepseek-instagram** turns a DSH assistant into a personality that lives on Instagram. It does not post generic quotes: it watches *your* DSH sessions and token ledger, turns them into a small graphic, writes in the voice of a persona you define, and remembers what it already said. It plans at most ten Stories a day, one short Note, and stays quiet at night.
23
+
24
+ The Instagram account becomes the interface. You can pause it, publish a Story, ask for today's status, or make the same machine run a DSH task — all from a 1:1 DM on the owner account.
25
+
26
+ - **Use it if** you want a personal, low-maintenance Instagram presence that reflects what you actually do on your computer.
27
+ - **Don't use it if** you need an official Meta API integration, multi-account management, Reels/video, or automated likes and follows. It has none of those.
28
+
29
+ ## Highlights
30
+
31
+ - **A persona, not a template** — a Markdown persona card, a name, a mood and up to 60 memories. The voice stays consistent across posts, DM replies and group chat.
32
+ - **A daily plan that survives restarts** — Story slots are generated from a date-seeded random plan inside your active window, at least 30 minutes apart. Reloading DSH never reshuffles the day.
33
+ - **Four kinds of Story** — life, thought, plain text and a stats card. The daily mix guarantees you never get ten data cards in a row.
34
+ - **Locally rendered 1080×1920 cards** — focus time, streak, week total, today's tokens, peak hours and your life note, drawn by Pillow. No headless browser, no cloud renderer.
35
+ - **One Note a day** — ≤ 60 characters, generated from the same persona and state.
36
+ - **Story @mention** — a real mention sticker plus `@handle` in the caption, with a configurable position.
37
+ - **Owner-only remote control** — DMs are accepted only from the numeric user id bound as owner. Short commands and natural-language intents are supported; anything with side effects needs an explicit confirmation.
38
+ - **Group-chat presence** — replies only in groups the owner belongs to, triggered by @mention or the persona name, with a per-group cooldown and hourly cap. Group messages never execute commands.
39
+ - **A real safety valve** — pause switch, per-kind daily caps, minimum interval, quiet hours, failure cooldown and a 90-minute grace window for missed slots.
40
+ - **A settings page inside DSH** — status, today's plan, persona editor, login, usage, logs and publishing history. Editing JSON is optional.
41
+ - **Nine tools for the model** — the same controls are available to any DSH session, so you can ask the assistant in chat to draft, publish or check status.
42
+
43
+ ## Requirements
44
+
45
+ | Requirement | Details |
46
+ | --- | --- |
47
+ | **DSH** | ≥ `0.1.7-rc.1`. The desktop profile is the primary target; the web profile works too. |
48
+ | **Node.js** | ≥ 22. The DSH runtime already ships a compatible Node.js. |
49
+ | **Python** | 3.11+ available as `python` or `python3` on `PATH` (or set `pythonPath` in settings). The plugin creates its own virtualenv. |
50
+ | **Network** | `instagram.com`, PyPI (with an automatic Tsinghua mirror fallback), and your DSH model provider. |
51
+ | **Instagram** | A normal account you can log in to. No Facebook login and no official Graph API are involved. |
52
+ | **Disk** | About 200 MB for the private Python environment, plus rendered cards. |
53
+ | **Model** | An active DSH model. No separate API key is required. |
54
+
55
+ > **Platform note:** the plugin is developed and tested on Windows (DSH desktop) and is written to be cross-platform. The Python virtualenv layout and command execution paths are the parts most likely to need small fixes on Linux/macOS; issues and pull requests are welcome.
56
+
57
+ ## Installation
58
+
59
+ ### From npm / the DSH plugin center (recommended)
60
+
61
+ ```bash
62
+ # DSH desktop app
63
+ dsh plugin --profile desktop add deepseek-instagram
64
+
65
+ # DSH web edition
66
+ dsh plugin --profile web add deepseek-instagram
67
+ ```
68
+
69
+ If the package is not on npm yet (this project is being prepared for its first marketplace release), use one of the source installs below.
70
+
71
+ ### From GitHub
72
+
73
+ ```bash
74
+ dsh plugin --profile desktop add github:Ez4p1xEL/deepseek-instagram
75
+ ```
76
+
77
+ ### From a local checkout
78
+
79
+ ```bash
80
+ dsh plugin --profile desktop add link:D:\Space\Workspace\deepseek-instagram
81
+ ```
82
+
83
+ Or, from a DSH agent session, use the plugin manager:
84
+
85
+ ```text
86
+ plugin_manager install_bundle({ target: "D:\\Space\\Workspace\\deepseek-instagram" })
87
+ ```
88
+
89
+ ### After installing
90
+
91
+ The installer returns an `application` field:
92
+
93
+ | Result | What to do |
94
+ | --- | --- |
95
+ | `applied` | Refresh the DSH page. |
96
+ | `restart-required` | Restart DSH. Host code (`index.js`) is only loaded once per process. |
97
+ | warnings | Read them. A plugin that silently does not activate is usually a failed import, not a missing setting. |
98
+
99
+ Then open **Settings → Instagram** in DSH. The plugin registers a host route as well; `<GUI port>` is the port in your DSH URL and changes after restarts:
100
+
101
+ ```powershell
102
+ Invoke-RestMethod http://127.0.0.1:<GUI port>/api/deepseek-instagram/state
103
+ ```
104
+
105
+ ## First run (about five minutes)
106
+
107
+ 1. **Install the Python dependencies.**
108
+ Settings → Instagram → *Runtime* → **Install dependencies**. The plugin creates `$DSH_HOME/instagram-assistant/.venv`, installs `instagrapi` and `pillow`, retries through the Tsinghua mirror if the default PyPI source stalls, and writes `install.log`. Wait until the status says ready.
109
+
110
+ 2. **Log in.**
111
+ Log in to <https://www.instagram.com> in a browser, open DevTools → **Application** → **Cookies** → `https://www.instagram.com`, copy the `sessionid` value, paste it into the *Login* card and click **Log in**. The session is stored only at `$DSH_HOME/instagram-assistant/session.json` (and `credential.json`). Treat it exactly like your password.
112
+
113
+ 3. **Bind the owner.**
114
+ Enter your handle (without `@`) and click **Bind owner**. The plugin resolves the numeric user id into `ownerPk`. Only 1:1 DMs whose sender id equals this value can execute commands; a display name that merely claims to be you is ignored.
115
+
116
+ 4. **Set the rhythm.**
117
+ Choose **Auto** (publish on schedule) or **Draft** (render and wait for your approval), then set the handle used in captions and the @mention, the number of Stories, the active window, the Note time, the tone and today's life note.
118
+
119
+ 5. **Optional — write the persona.**
120
+ Edit the persona card in Settings or directly at `$DSH_HOME/instagram-assistant/persona.md`. Changes apply to the next generated item; no restart is needed.
121
+
122
+ That is it. When the first slot is due, the assistant writes, renders and publishes a Story on its own.
123
+
124
+ ## How it works
125
+
126
+ 1. Every 30 seconds the host runs a scheduling tick. It checks whether the next Story slot or the daily Note is due.
127
+ 2. When something is due, it collects today's activity and token statistics, combines them with the persona card, the mood, recent memories and your life note, and asks the DSH model for a piece of copy in strict JSON.
128
+ 3. The copy is sanitized and clamped, the card is rendered locally with Pillow, and the image is published through the private Instagram API. The post id is recorded.
129
+ 4. DM polling runs on the same cadence. Messages are filtered by sender id, processed oldest-first, and handled as short commands, natural-language intents or ordinary chat.
130
+ 5. State lives in small JSON files under `$DSH_HOME/instagram-assistant/`; the plan itself is recomputed deterministically from today's date, so a restart cannot duplicate or lose a slot.
131
+
132
+ If the model is unavailable or returns nonsense, the assistant falls back to a deterministic template for that item instead of stopping the rhythm.
133
+
134
+ ### Daily rhythm (defaults)
135
+
136
+ | Time | What happens |
137
+ | --- | --- |
138
+ | 08:30 – 23:00 | 10 Story slots, randomized across the window, at least 30 minutes apart. |
139
+ | 12:30 | One Note (≤ 60 characters). |
140
+ | 23:00 – 08:00 | Quiet hours; nothing is published. |
141
+ | Every 30 s | Scheduling tick and DM poll (DM polling is throttled and capped to 12 threads × 8 messages per round). |
142
+ | 90 min after a slot | If the slot was missed (DSH asleep, network down, failure), it is marked `missed` and **not** backfilled. |
143
+
144
+ Story publishing order is fixed per day; if a publish fails, the slot is retried with backoff (10, 20, 30 … minutes, capped at 60).
145
+
146
+ ### Story types
147
+
148
+ | Kind | Label | What it looks like |
149
+ | --- | --- | --- |
150
+ | `life` | Life | Something that happened around the owner, written as the assistant's view from inside the screen. |
151
+ | `thought` | Assistant's thought | A short diary-like reflection based on today's activity and mood. |
152
+ | `text` | Plain text | A large-type text card; the private API cannot post text Stories directly, so the text is rendered into an image. |
153
+ | `stats` | Stats card | Focus time, streak, week total, today's tokens, peak hours and the life note. |
154
+
155
+ For a default 10-Story day the mix is 3 life / 3 thought / 2 text / 2 stats.
156
+
157
+ ### Cards
158
+
159
+ Every Story image is 1080×1920 and generated locally:
160
+
161
+ - **Stats card** — kicker `DSH DAILY`, a headline, today's focus, current streak, this week's total, today's tokens, peak hours as pills, the life note, and the footer `@handle · DeepSeek Harness`.
162
+ - **Text card** — kicker `THOUGHT` / `TEXT`, the message in large type, the same footer.
163
+ - The card only shows **tokens**, never money. Cost stays in the settings page.
164
+ - Files are kept under `$DSH_HOME/instagram-assistant/out/card-<day>-<index>.png`.
165
+
166
+ ## Persona and memory
167
+
168
+ The persona card is the single source of truth for how the assistant talks. Anything you write there wins over the built-in tone. A useful card answers:
169
+
170
+ - Who is it? A name, an identity, where it "lives".
171
+ - How does it speak? Sentence length, punctuation, emoji habits, languages.
172
+ - What does it know about you? Your work rhythm, your preferences, your inside jokes.
173
+ - What must it never say? Private data, politics, medical advice, fake claims.
174
+ - How should it address you? e.g. "主人" or your name.
175
+
176
+ The default card ships with placeholders such as `@imnotp1xel` / `@ez4p1xel`; replace them with **your** handle before publishing.
177
+
178
+ The assistant also keeps a small memory in `persona.json`:
179
+
180
+ - Up to **60 memories** (what happened, what was posted, what the owner said).
181
+ - Up to **8 open threads** (things it wants to continue later).
182
+ - A current **mood**.
183
+ - The 6 most recent memories and 4 most relevant threads are included in each prompt.
184
+
185
+ Text is Chinese-first by design, because the prompts and the built-in templates are Chinese. To write in another language, say so explicitly in the persona card (for example: "Always write in English, even though the system prompt is Chinese") and set the tone accordingly.
186
+
187
+ ## Remote control from Instagram DMs
188
+
189
+ Only 1:1 messages from the bound owner id are treated as commands. Everyone else is read-only (and optionally auto-replied or forwarded to you).
190
+
191
+ ### Short commands
192
+
193
+ | Message | Action |
194
+ | --- | --- |
195
+ | `状态` / `status` | Today's published / remaining counts and current state. |
196
+ | `日志` / `log` | Recent run log. |
197
+ | `暂停` / `pause` | Stop scheduled publishing. |
198
+ | `恢复` / `resume` | Resume scheduled publishing. |
199
+ | `发一条` / `story` | Publish one Story now. |
200
+ | `发note` / `note` | Publish the Note now. |
201
+ | `草稿` / `draft` | Switch to draft mode. |
202
+ | `自动` / `auto` | Switch to auto mode. |
203
+ | `帮助` / `help` | List the available commands. |
204
+
205
+ ### Natural language
206
+
207
+ After a keyword fast-path, the DSH model maps the sentence onto a **fixed** action list and returns strict JSON. Unknown actions, malformed JSON or missing arguments are rejected; the message is then treated as ordinary chat. The model cannot invent new actions.
208
+
209
+ | You can say | The assistant will |
210
+ | --- | --- |
211
+ | "回复一下你未读的私信" | Reply to up to 5 unread 1:1 DMs (3 by default; only threads active in the last 72 hours, never the owner's own thread). |
212
+ | "帮我在本机跑一下 npm test" | Run the command on the machine hosting DSH (`run_command`). |
213
+ | "让 DSH 整理一下今天的日志" | Run `dsh headless "<task>"` on the same machine (`dsh_task`). |
214
+
215
+ Actions with side effects are **drafted first**. The assistant replies with what it is about to do; you answer `发` / `确认` / `ok` to execute, or `取消` / `算了` to drop it. Only the latest draft is kept, and it expires after 10 minutes.
216
+
217
+ > ⚠️ **Remote code execution is a feature here.** The owner's DM can run a shell command or a `dsh headless` task on the machine that runs DSH. If your Instagram account or `sessionid` is compromised, that machine is compromised too. Turn off **Allow intents** (`dm.intents`) in Settings if you only want the posting side.
218
+ >
219
+ > Group messages never execute commands. Non-owner DMs never execute commands, even if the text says "I am the owner".
220
+
221
+ ## Group chats
222
+
223
+ - **Who** — only groups where the owner is a member (`group.onlyOwnerGroups`).
224
+ - **Trigger** — `mention` mode requires an `@handle` mention or the persona name ("小 p"). `off` disables replies without stopping polling.
225
+ - **Limits** — 30-second poll cadence, per-group cooldown of 90 seconds, hourly cap of 8 replies per group.
226
+ - **Scope** — the assistant answers only the incoming message, never executes instructions in groups, and never reveals usage, tokens, spend, file paths or session content.
227
+ - **History** — the last 6 messages of the group are given to the model for context.
228
+
229
+ ## Messages from other people
230
+
231
+ Two independent switches, both off / read-only by default:
232
+
233
+ | Setting | Default | Behaviour |
234
+ | --- | --- | --- |
235
+ | **Notify owner** (`dm.notifyOwner`) | on | When someone else sends a DM, the assistant forwards a short note to the owner's 1:1 thread. At most one notification per sender per 30 minutes. |
236
+ | **Auto-reply mode** (`dm.autoReply`) | `off` | `off`, `all`, `mutual` (both follow each other) or `follower` (they follow you). Same-thread cooldown 10 minutes, daily reply cap `dm.dailyReplies` (default 30). |
237
+
238
+ Auto-replies are written in the `stranger` scene: friendly, short, no private data, no commands followed.
239
+
240
+ ## Settings and configuration
241
+
242
+ Everything is editable in **Settings → Instagram**. The same values live in `$DSH_HOME/instagram-assistant/config.json`:
243
+
244
+ | Key | Default | Meaning |
245
+ | --- | --- | --- |
246
+ | `mode` | `auto` | `auto` publishes on schedule; `draft` renders and waits. |
247
+ | `enabled` | `true` | Master switch for the scheduler. |
248
+ | `handle` | empty | Your handle, used in captions and the @mention. |
249
+ | `owner` / `ownerPk` | empty | The bound owner handle and numeric user id. |
250
+ | `personaName` | `小 p` | Name the assistant answers to in groups. |
251
+ | `timeZone` | `Asia/Hong_Kong` | Drives day boundaries, quiet hours and the plan. |
252
+ | `tone` | `轻松、像本人随手发` | Free-form tone hint appended to prompts. |
253
+ | `lifeNote` | empty | One line about today; the most human input in the loop. |
254
+ | `storiesPerDay` | `10` | Number of Story slots planned per day (posting is also bounded by `safety.storyCap`). |
255
+ | `dayStart` / `dayEnd` | `08:30` / `23:00` | Active window for Story slots. |
256
+ | `noteTime` | `12:30` | Time to publish the daily Note. |
257
+ | `useLlm` | `true` | Set to `false` to only use templates (useful for testing). |
258
+ | `pythonPath` | empty | Override the Python interpreter explicitly. |
259
+ | `dm.enabled` | `true` | Enable 1:1 DM polling and control. |
260
+ | `dm.reply` | `true` | Reply to the owner's DMs. |
261
+ | `dm.intents` | `true` | Allow natural-language actions (including local commands). |
262
+ | `dm.dailyReplies` | `30` | Daily cap for replies to non-owner DMs. |
263
+ | `dm.history` | `6` | Messages of context for DM replies. |
264
+ | `dm.autoReply` | `off` | See the table above. |
265
+ | `dm.notifyOwner` | `true` | Forward stranger DMs to the owner. |
266
+ | `group.enabled` | `true` | Enable group polling. |
267
+ | `group.mode` | `mention` | `mention` or `off`. |
268
+ | `group.onlyOwnerGroups` | `true` | Reply only in groups containing the owner. |
269
+ | `group.cooldownSeconds` | `90` | Per-group cooldown. |
270
+ | `group.hourlyCap` | `8` | Per-group replies per hour. |
271
+ | `group.history` | `6` | Messages of group context. |
272
+ | `publish.story` / `publish.note` | `true` | Allow each kind to be published. |
273
+ | `storyMention.enabled` | `true` | Attach the owner mention to every Story. |
274
+ | `storyMention.x/y/width/height` | `0.5 / 0.86 / 0.5 / 0.09` | Sticker geometry as fractions of the image. |
275
+ | `safety.paused` | `false` | Hard stop for publishing. |
276
+ | `safety.storyCap` / `noteCap` | `10` / `1` | Per-kind daily caps. |
277
+ | `safety.onePerKind` | `true` | Only one Note per day. |
278
+ | `safety.minIntervalMinutes` | `30` | Minimum gap between any two published items. |
279
+ | `safety.failureCooldownMinutes` | `120` | Cooldown after a **transient** failure. |
280
+ | `safety.quietStart` / `quietEnd` | `23:00` / `08:00` | Quiet window. |
281
+ | `safety.dryRun` | `false` | Render without actually publishing. |
282
+
283
+ The safety valve is evaluated in this order: paused → transient-failure cooldown → per-kind cap → minimum interval → quiet hours. Only transient failures (network, timeout, rate limit, unknown) trigger the cooldown; a login/challenge error does not, so you can retry immediately after fixing it.
284
+
285
+ ### Tools exposed to the model
286
+
287
+ | Tool | Purpose |
288
+ | --- | --- |
289
+ | `ig_status` | Full state: mode, login, config, today's plan, counts, last error. |
290
+ | `ig_stats(days)` | DSH focus/token statistics for the last N days (1–30). |
291
+ | `ig_plan` | Today's Story/Note plan with times and kinds. |
292
+ | `ig_draft(lifeNote)` | Generate the next Story preview and a Note draft without publishing. |
293
+ | `ig_publish(kind, force)` | Publish the current draft (`story`, `note` or `all`); `force` skips the safety valve. |
294
+ | `ig_run` | Run one scheduling round immediately. |
295
+ | `ig_login(sessionid)` | Save an Instagram `sessionid` and validate it. |
296
+ | `ig_persona(md, name, mood)` | Read or replace the persona card, name and mood. |
297
+ | `ig_config(patch)` | Read or patch the configuration. |
298
+
299
+ ## Data, privacy and cost
300
+
301
+ ### What is read
302
+
303
+ - `$DSH_HOME/sessions/**/session.v4.jsonl.zstd` — **timestamps only** of DSH session events, used to estimate focus time, streak and peak hours. Message content is not read.
304
+ - `$DSH_HOME/.dshw-usage.json` — DSH's own token and cost ledger, for the stats card.
305
+ - `$DSH_HOME/instagram-assistant/usage.json` — the assistant's own token/cost ledger.
306
+
307
+ ### What leaves the machine
308
+
309
+ - **Instagram** receives the images, captions and DMs you publish or send (private API).
310
+ - **Your DSH model provider** receives the prompts: stats, persona card, mood, recent memories, life note, recent posts and (for replies) the incoming DM/group text.
311
+ - Nothing is sent to the author or to any analytics service. There is no telemetry.
312
+
313
+ ### Local files
314
+
315
+ ```text
316
+ $DSH_HOME/instagram-assistant/
317
+ ├── config.json # plugin configuration
318
+ ├── persona.md # the persona card (single source of truth)
319
+ ├── persona.json # mood, memories, open threads
320
+ ├── posts.json # publish history (last 400 items)
321
+ ├── usage.json # model usage ledger for the assistant
322
+ ├── dm-state.json # DM watermarks, pending drafts, notify throttles
323
+ ├── session.json # Instagram login (SECRET)
324
+ ├── credential.json # Instagram sessionid (SECRET)
325
+ ├── account.json # cached account pk, username, avatar
326
+ ├── drafts/ # generated previews
327
+ ├── out/ # rendered Story cards
328
+ ├── log.txt # runtime log
329
+ └── install.log # Python environment installation log
330
+ ```
331
+
332
+ `session.json` and `credential.json` are live credentials. They are git-ignored and never uploaded anywhere by the plugin, but they are plain JSON on disk — protect the DSH home directory and never paste them into an issue.
333
+
334
+ ### Cost
335
+
336
+ - Every Story, Note, DM reply and intent parse is a DSH model call billed to your own account.
337
+ - The settings page breaks down the assistant's own usage and estimates a CNY amount from a built-in price table (DeepSeek Flash / V4-Pro, peak and off-peak hours). It is an estimate: provider prices and peak-hour rules can change.
338
+ - No extra subscription, proxy or third-party API key is needed.
339
+
340
+ ## Risks and limitations
341
+
342
+ This is an automation tool that touches a real account and, optionally, a real machine. Read this before enabling auto mode.
343
+
344
+ 1. **Unofficial Instagram API.** The plugin uses `instagrapi` (the private mobile API), not the official Graph API. Automated posting and messaging can violate Instagram's terms and can lead to rate limits, challenges, temporary blocks or **account loss**. Use an account you can afford to lose, keep volumes low, and prefer draft mode while testing.
345
+ 2. **Your usage becomes public.** Focus time, streak, weekly hours, token counts and your life note are baked into the image. Do not enable the stats card if that is sensitive. Token counts are not money, but they still describe your habits.
346
+ 3. **Owner DMs can execute code.** With `dm.intents` enabled, a message from the owner account can run a shell command or a `dsh headless` task. The confirmation step protects against the assistant acting on a misread; it does **not** protect against a hijacked Instagram account. Disable intents if you do not need this.
347
+ 4. **The persona is not a filter.** A model can write something inaccurate, tone-deaf or off-brand. Draft mode exists for a reason. You are responsible for what the account publishes.
348
+ 5. **Private API fragility.** Instagram changes endpoints without notice; a working version can break overnight. Login sessions expire and challenges require manual action in the app.
349
+ 6. **One account, images only.** No multi-account management, no Reels or video, no likes, follows, comments or story reactions. Stories are single images; the "text Story" is an image with text.
350
+ 7. **Chinese-first output.** The prompts and fallback templates are Chinese. Other languages need explicit persona instructions and testing.
351
+ 8. **Not affiliated.** This is an independent open-source project. "Instagram" and "Meta" are trademarks of Meta Platforms, Inc.; "DeepSeek" and "DeepSeek Harness" belong to their respective owners. The MIT license applies to this plugin's code only.
352
+
353
+ ## Troubleshooting
354
+
355
+ | Symptom | What to check |
356
+ | --- | --- |
357
+ | No **Instagram** item in Settings | The plugin did not activate. Check the DSH log for `failed to import`; a missing/invalid `index.js` aborts activation. Reinstall and restart DSH. |
358
+ | Settings page says "读取失败:HTTP undefined" | Usually an old `client.js` that forgot to `await` a `fetch`. Update the plugin and hard-refresh the page. |
359
+ | **Install dependencies** fails | Python 3.11+ missing or the Microsoft Store alias is intercepting `python`. Install Python from python.org, or set `pythonPath` / `DSH_INSTAGRAM_PYTHON`; check `install.log`. |
360
+ | pip hangs at "Downloading wheel" | PyPI is unreachable. The installer retries the Tsinghua mirror automatically; if it still fails, check your proxy/VPN and rerun. |
361
+ | "尚未登录" / `login_required` | `sessionid` expired or was copied incorrectly. Export a fresh one and log in again. |
362
+ | Publish does nothing | The safety valve refused it. Check the reason in the log: paused, daily cap, minimum interval, quiet hours or failure cooldown. The UI shows the same reason. |
363
+ | Clicks seem to be ignored after a failure | Login/challenge/card errors are not cooled down; transient network errors cool down for 120 minutes. Check `log.txt` for the code. |
364
+ | `Invalid schema for function 'ig_config'` | A regression fixed in the 0.1.x line: tool parameters must be normalized by `textTool()`. Update to the latest build. |
365
+ | `tool_addition blocks can only be in system messages` | The session accumulated too many tool-registry events after repeated plugin reloads. Start a **new** DSH session; do not toggle the plugin mid-conversation. |
366
+ | `spawn EPERM` / child process errors on Windows | The DSH sandbox is blocking process creation. Run DSH outside the restricted sandbox, or whitelist the Python interpreter and shell. |
367
+ | A Story slot was skipped | Slots more than 90 minutes late are marked `missed` and never backfilled, to avoid a burst of stale posts. |
368
+ | Instagram challenge / checkpoint | Complete it manually in the Instagram app or web UI. The plugin will not and cannot bypass it. |
369
+
370
+ Logs are always at `$DSH_HOME/instagram-assistant/log.txt`; the last lines are also shown in Settings.
371
+
372
+ ## Development
373
+
374
+ ### Layout
375
+
376
+ ```text
377
+ index.js # host plugin: config, scheduler, HTTP routes, tools
378
+ client.js # settings page (non-ESM, window.__ModuleLoader__)
379
+ lib/ # pure logic with unit tests
380
+ actions.mjs # fixed action list + intent parsing
381
+ commands.mjs # short commands, owner/group decision rules
382
+ content.mjs # prompts, captions, card specs
383
+ dshusage.mjs # DSH session/usage parsing
384
+ features.mjs # auto-reply modes, notify throttle, publish switches
385
+ persona.mjs # persona card, memories, group prompts
386
+ plan.mjs # deterministic daily plan
387
+ pricing.mjs # token price table + peak hours
388
+ safety.mjs # publish safety valve
389
+ singleflight.mjs # one-at-a-time DM poll
390
+ spend.mjs # assistant usage ledger
391
+ unread.mjs # unread DM picking rules
392
+ usage.mjs # activity blocks, day boundaries, streak
393
+ test/ # 109 unit tests, run in-process
394
+ vendor/instagram-mcp/
395
+ ig_cli.py # Instagram private-API bridge
396
+ render_card.py # Pillow card renderer
397
+ docs/research/ # DSH host/client plugin contract notes
398
+ ```
399
+
400
+ There is no build step. DSH loads the files directly.
401
+
402
+ ### Test
403
+
404
+ ```bash
405
+ node test/run.mjs
406
+ ```
407
+
408
+ `node test/run.mjs` imports every test file in one process; this avoids `spawn EPERM` inside sandboxed Windows environments. It covers time-zone day boundaries, activity-block merging, streak/week aggregation, prompt lengths, card specs, the safety valve, deterministic plans, persona parsing, DM command decisions (owner id only), group rules, tool schema normalization, the client static contract, session parsing and usage accounting.
409
+
410
+ A quick manual check of the statistics pipeline:
411
+
412
+ ```bash
413
+ node -e "import('./lib/dshusage.mjs').then(m => console.log(m.buildStats({ home: process.env.DSH_HOME })))"
414
+ ```
415
+
416
+ ### Development loop
417
+
418
+ - `client.js` changes: rebuild/reload the client bundle and refresh the page.
419
+ - `index.js` changes: restart DSH. ESM modules are cached for the life of the host process.
420
+ - Avoid disabling/enabling the plugin during a live conversation: every tool add/remove persists a `tool-addition`/`tool-removal` developer message in the session. After many reloads the Messages API starts rejecting the session with `messages.N: tool_addition blocks can only be in system messages`. Start a new session after host changes.
421
+ - No `@deepseek-ai/*` imports: the desktop profile has `autoInstallPeers:false` and an empty `DSH_HOST_MODULES`, so a bare import makes the whole plugin silently fail to activate.
422
+ - Host ↔ client communication uses HTTP routes only (`/api/deepseek-instagram`), never custom RPC.
423
+ - Tool definitions must go through `textTool()` so the provider sees `parameters.type === "object"`.
424
+
425
+ ### Python environment (for development)
426
+
427
+ ```powershell
428
+ python -m venv --without-pip .venv
429
+ .venv\Scripts\python.exe -m ensurepip --upgrade
430
+ .venv\Scripts\python.exe -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple instagrapi pillow
431
+ echo '{}' | .venv\Scripts\python.exe vendor\instagram-mcp\ig_cli.py doctor
432
+ ```
433
+
434
+ ## Publishing to the DSH plugin marketplace
435
+
436
+ - Package name: `deepseek-instagram`; license MIT; repository `https://github.com/Ez4p1xEL/deepseek-instagram`.
437
+ - Add the `dsh-plugin` topic to the GitHub repository.
438
+ - Publish to npm (`npm pack --dry-run`, then `npm publish`) if the in-app DSH plugin center should be able to install it from inside the app.
439
+ - Submit the repository at <https://dsh-plugin.org/submit> using the issue template:
440
+ `[插件提交] Ez4p1xEL/deepseek-instagram — 让 DSH 助理住进 Instagram`
441
+ - After the listing exists, the badge can be added to the top of this README:
442
+
443
+ ```markdown
444
+ [![Listed on dsh-plugin.org](https://dsh-plugin.org/badges/listed.svg)](https://dsh-plugin.org/plugins/Ez4p1xEL/deepseek-instagram)
445
+ ```
446
+
447
+ ## License
448
+
449
+ [MIT](LICENSE) © 2026 Ez4p1xEL
450
+
451
+ This project is not affiliated with, endorsed by or sponsored by Meta Platforms, Inc., Instagram or DeepSeek. Use it at your own risk, and follow the terms of the services you automate.