Merge OrbitOS into project — one install, everything ready

- Added 15 OrbitOS skills (bundled in skills/orbitos/)
- Added vault structure templates (views, templates, prompts)
- Added install.sh (macOS + Linux)
- Removed references/orbitos-skills.md (no longer needed)
- Updated README: 30 skills total, unified install flow

Total: 9 mm* + 6 dependencies + 15 orbitos = 30 skills
This commit is contained in:
Kunthawat Greethong
2026-07-02 10:13:46 +07:00
parent 7bf147069e
commit ddac3f187c
45 changed files with 2695 additions and 197 deletions

View File

@@ -0,0 +1,209 @@
---
name: orbites-ai-newsletters
description: Curate daily AI, Online Marketing, SEO, and AI×Marketing Research news digest. For OrbitOS. Use when user says 'AI news', 'marketing news', 'SEO news', 'newsletter digest', 'what's new in AI', 'ข่าว AI', 'ข่าว marketing', 'สรุปข่าว'.
---
# OrbitOS: Daily News Digest — AI · Marketing · SEO · Research
Fetch, deduplicate, and rank news from 5 curated topic areas into a daily digest saved to the OrbitOS vault.
## Source Configuration
### 🔵 AI News
| Source | URL | Type |
|--------|-----|------|
| TLDR AI | `https://bullrich.dev/tldr-rss/ai.rss` | RSS |
| The Rundown AI | `https://rss.beehiiv.com/feeds/2R3C6Bt5wj.xml` | RSS |
### 🟢 Online Marketing
| Source | URL | Type |
|--------|-----|------|
| Marketing AI Institute | `https://www.marketingaiinstitute.com/blog/rss.xml` | RSS |
| HubSpot Marketing | `https://blog.hubspot.com/marketing/rss.xml` | RSS |
| Search Engine Land | `https://searchengineland.com/feed` | RSS |
### 🟡 SEO
| Source | URL | Type |
|--------|-----|------|
| Search Engine Journal | `https://www.searchenginejournal.com/feed/` | RSS |
| Ahrefs Blog | `https://ahrefs.com/blog/feed/` | RSS |
| Semrush Blog | `https://www.semrush.com/blog/feed/` | RSS |
| Moz Blog | `https://feedpress.me/mozblog` | RSS |
| Neil Patel | `https://neilpatel.com/blog/feed/` | RSS |
### 🟣 Marketing & AI Research
| Source | URL | Type |
|--------|-----|------|
| arXiv (AI + marketing) | `https://export.arxiv.org/api/query?search_query=all:marketing+AND+all:AI&sortBy=submittedDate&sortOrder=descending&max_results=10` | API |
| Web search | Execute: `web_search("AI marketing research 2026 generative AI")` + `web_search("marketing AI agent study 2026")` | Search |
## Workflow
1. **Check cache**: Look for `50_Resources/Newsletters/YYYY-MM/YYYY-MM-DD-Digest.md` (relative to vault root). If exists with today's date, return cached content.
2. **Fetch feeds** (see Provider Fallbacks for exact curl commands):
- RSS sources: Use `curl` via terminal on each URL. Parse title, link, pubDate, description from XML. Fall back to `web_extract` if configured.
- arXiv: Use `curl` on the API URL. Parse `<entry>` elements.
- Web search: Run via `web_search` if configured; otherwise skip this section.
3. **Classify each item** into topic buckets:
- `ai` — LLMs, GPT, Claude, agents, ML, AI tools
- `marketing` — digital marketing, paid ads, content strategy, brand, B2B marketing
- `seo` — search rankings, Google updates, SERP features, technical SEO, GEO
- `research` — academic papers, studies, surveys, reports with data/statistics
4. **Deduplicate**: Items with 70%+ title word overlap across sources → merge into one entry tracking all source URLs.
5. **Rank within each bucket** by:
- Relevance to the topic cluster
- Content creation potential (can I write a post about this?)
- Novelty (penalize if similar item in recent archives)
- Recency
6. **Generate digest** — bilingual Thai/English:
```markdown
# 📰 Daily Digest — YYYY-MM-DD
## 🔵 AI — Top 3
- **[Title]** — 1-line summary. [Source]
*Angle:* content idea in Thai
...
## 🟢 Online Marketing — Top 3
...
## 🟡 SEO — Top 3
...
## 🟣 Marketing & AI Research — Top 2
...
## 💡 Content Creation Opportunities
Top 5 across all buckets ranked by post potential:
1. ...
```
7. **Save files** (all paths relative to vault root):
- `50_Resources/Newsletters/YYYY-MM/YYYY-MM-DD-Digest.md` — curated digest
- `50_Resources/Newsletters/YYYY-MM/Raw/` — raw extracted content per source if substantial
8. **Curate high-value articles → migrate to 30_Research/**
- After generating the digest, scan Content Creation Opportunities and related articles
- For each article worth keeping for future content creation:
1. Copy/save as `30_Research/<slug-title>.md` with frontmatter `type: article` + source URL
2. Remove from `Raw/` folder (don't keep raw dumps there long-term)
3. Add a note in the Research file linking back to the digest
- The user confirmed this: **`Raw/` = processing cache, `30_Research/` = permanent collection**
- Pitfall: Don't let Raw/ accumulate — it's a temp folder, not an archive
- See `references/article-curation-workflow.md` for the full process
## Output Format
**Manual invocation (user asks directly):** Display full digest with all 4 topic sections + content opportunities.
**From start-my-day cron (07:00):** Return condensed list:
```
**📰 Morning Briefing:**
🔵 AI: [N items] — top headline
🟢 Marketing: [N items] — top headline
🟡 SEO: [N items] — top headline
🟣 Research: [N items] — top headline
Full digest: [[YYYY-MM-DD-Digest]]
```
## Provider Fallbacks
`web_extract` and `web_search` may be unavailable (no provider configured). **Primary approach is `curl` via terminal.** Only use `web_extract`/`web_search` if they return data.
### Fetch commands (preferred — curl + terminal)
```bash
# RSS feeds: curl + parse XML inline
curl -sL --max-time 15 "https://bullrich.dev/tldr-rss/ai.rss" | head -500
curl -sL --max-time 15 "https://rss.beehiiv.com/feeds/2R3C6Bt5wj.xml" | head -500
curl -sL --max-time 15 "https://www.marketingaiinstitute.com/blog/rss.xml" | head -500
curl -sL --max-time 15 "https://blog.hubspot.com/marketing/rss.xml" | head -500
curl -sL --max-time 15 "https://searchengineland.com/feed" | head -500
curl -sL --max-time 15 "https://www.searchenginejournal.com/feed/" | head -500
curl -sL --max-time 15 "https://ahrefs.com/blog/feed/" | head -500
curl -sL --max-time 15 "https://www.semrush.com/blog/feed/" | head -500
curl -sL --max-time 15 "https://feedpress.me/mozblog" | head -500
curl -sL --max-time 15 "https://neilpatel.com/blog/feed/" | head -500
# arXiv API (XML — parse <entry> elements)
curl -sL --max-time 15 "https://export.arxiv.org/api/query?search_query=all:marketing+AND+all:AI&sortBy=submittedDate&sortOrder=descending&max_results=10" | head -300
# For truncated large feeds, extract titles only:
curl -sL --max-time 15 "https://rss.beehiiv.com/feeds/2R3C6Bt5wj.xml" | grep -o '<title>[^<]*</title>' | head -15
```
## Source Health Notes
| Source | Status | Note |
|--------|--------|------|
| TLDR AI | ✅ Active | `bullrich.dev/tldr-rss/ai.rss` — reliable, rich descriptions |
| The Rundown AI | ✅ Active | `rss.beehiiv.com` — HTML entities in titles (`&#39;`), use grep for title extraction if truncated |
| Marketing AI Institute | ✅ Active | Blog posts weekly, HubSpot-hosted |
| HubSpot Marketing | ✅ Active | Very large feed, head -500 sufficient for recent items |
| Search Engine Land | ✅ Active | WordPress RSS, standard format |
| Search Engine Journal | ✅ Active | WordPress RSS, frequent updates |
| Ahrefs Blog | ✅ Active | Fresh content, enterprise SEO focus |
| Semrush Blog | ✅ Active | Data-driven SEO, frequent posts |
| Moz Blog | ✅ Active | **Fixed in June 2026** — URL changed from `moz.com/blog/feed``feedpress.me/mozblog` |
| Neil Patel | ✅ Active | Marketing + SEO insights, daily posts |
| Google Search Central | ❌ Permanently broken | `developers.google.com/search/blog/feed` 404 — blog discontinued/unhosted as of 2026 |
| arXiv API | ✅ Active | XML Atom feed, parse `<entry>` elements |
| Web Search | ⚠️ Config-dependent | Requires `web.search_backend` configured via `hermes tools` |
## Cron Mode Constraints
- **`execute_code` is BLOCKED in cron mode.** Use individual `terminal` calls instead. Batch parallel `curl` fetches as separate tool calls in one response.
- **`web_search` and `web_extract` may be unavailable** if not configured at the profile level.
- When a tool fails with "No provider configured", silently fall back to `curl` + `terminal` — do not abort.
## Content Creation Bridge
After generating the digest, the user may ask to write articles from the news items. When doing so, follow the **Research-First** approach documented in `references/news-to-article.md`.
### Research-First: News → Article Pipeline
1. **Identify the source articles** linked in each news item — don't write from the digest summary alone
2. **Read the original source articles** — use `curl -sL --max-time 20` with `python3 -c` for HTML text extraction; fall back to `browser_navigate` for Cloudflare/Vercel-protected sites
3. **Extract key data**: specific numbers, quotes, mechanisms, and causal relationships
4. **Synthesize multiple sources** into a coherent single narrative — don't just restate one article
5. **Write in Thai** with:
- 📌 "Takeaway" callout boxes per section (labeled by topic, e.g. "GEO Takeaway", "Content Strategy Takeaway")
- Data tables with comparison columns and emoji indicators (✅/❌/🟢/🟡/🔴)
- A summary table of actionable takeaways at the end (with bulletproof reasoning column)
- Source citations at the bottom linking back to originals
6. **Save article** to `~/vault/60_Articles/<slug>/article.md` with title/description/date/category/tags in frontmatter
7. **Save brief** — optionally create a brief.md in the same 60_Articles/<slug>/ directory with the research notes and source summaries
### Research fallback handling
When `web_extract` and `web_search` have no provider configured (common in this profile):
- **Generic HTML articles**: `curl -sL --max-time 20 "<URL>" | python3 -c "import sys,re; html=sys.stdin.read(); html=re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL); html=re.sub(r'<style[^>]*>.*?</style>', '', html, flags=re.DOTALL); text=re.sub(r'<[^>]+>', ' ', html); text=re.sub(r'\s+', ' ', text).strip(); print(text[:15000])"`
- **Sites with article tag**: Target `<article>` element specifically: `re.search(r'<article[^>]*>(.*?)</article>', html, re.DOTALL)` then strip tags
- **Cloudflare/Vercel blocked sites**: Fall back to `browser_navigate` + `browser_snapshot(full=true)` or browser_scroll for longer articles
- **VentureBeat**: Known to have Vercel security checkpoint; always use browser tools (curl won't work)
- See `orbites-ai-products` skill for the HN Algolia API and GitHub Search API curl patterns
### Thai content conventions
- Title: Hook-driven, ≤ 60 chars, includes curiosity gap or contrarian claim
- Opening paragraph: Hook that breaks reader expectation (not throat-clearing)
- Structure per section: Data table → explanation paragraph → 📌 Takeaway box
- End with: "ที่มา:" section listing all source articles as markdown links
- Avoid: generic "ในโลกดิจิทัลวันนี้" openings, artificial FAQ, keyword stuffing
## Error Handling
- One source down: Skip, note in section header "(1 source unavailable)"
- All sources in a topic down: Show "⚠️ No new items today" for that section
- All sources down: Use yesterday's digest with warning
- arXiv returns empty: Skip research section gracefully
- Web search rate-limited: Use cached web results or skip
- Terminal output truncated (>50KB): Use `grep` to extract key fields (titles, links)
- Google Search Central 404: Skip silently, note in source summary
- Moz stale: Skip entirely unless user asks for historical SEO content

View File

@@ -0,0 +1,64 @@
# Article Curation Workflow — Daily Digest → 30_Research/
## Why
The daily digest generates a raw dump in `50_Resources/Newsletters/YYYY-MM/Raw/`.
The user confirmed that high-value articles should **not** stay in Raw/ — they belong in `30_Research/` as permanent reference files.
User's exact words: *"จำเรื่องนี้ไว้เลยนะ"* (remember this). The confirmed flow:
```
Raw/ (temp cache)
↓ select high-value articles
30_Research/<slug-title>.md (permanent)
Referenced from future digest or content planning
```
## Selection Criteria
From the digest's Content Creation Opportunities section or notable articles:
- High content creation potential (LinkedIn post, blog, tutorial)
- Novel research or data-driven insights
- Actionable for the user's SEO/marketing work (brand visibility, AI search, GEO)
- Topic fits the user's niche (AI × Marketing, SEO, agentic systems)
## File Format
```markdown
---
type: article
source: https://example.com/article
source_digest: "[[50_Resources/Newsletters/YYYY-MM/YYYY-MM-DD-Digest]]"
captured: YYYY-MM-DD
tags: [article, ai-marketing, brand-visibility]
---
# [Article Title]
## Key Takeaways
- ...
- ...
## Why This Matters for Moreminimore
- ...
- ...
## Action Items
- [ ] Consider for LinkedIn post
- [ ] Reference in [project name] content plan
```
## Cleanup
- Remove the source raw file from `Raw/` after migrating
- If multiple articles from same raw file, remove after last migration
- Keep the digest itself (it's the curated summary, not the cache)
## Example
Article `chatgpt-opens-ads-all.md` was moved from:
```
50_Resources/Newsletters/2026-06/Raw/ → 30_Research/chatgpt-opens-ads-all.md
```

View File

@@ -0,0 +1,138 @@
# News-to-Article Workflow Reference
Full workflow for taking news items / content ideas from a digest and writing in-depth articles.
## Article Directory Structure
```
~/vault/60_Articles/
├── YYYY-MM-DD-<slug>/
│ ├── article.md # Full article with frontmatter (title, description, date, category, tags, status: draft)
│ ├── brief.md # Optional: research notes, source summaries, angles considered
│ └── images/ # Featured + inline images
│ └── featured.png
└── YYYY-MM-DD-<slug2>/
...
```
## Article Frontmatter Template
```yaml
---
title: "Hook-driven title (≤ 60 chars, Thai)"
description: "SEO meta description (120-160 chars)"
slug: "yyyy-mm-dd-kebab-case-slug"
date: YYYY-MM-DD
category: SEO | AI | Marketing | Research
author: Macky
tags: [Tag1, Tag2, Tag3, Tag4]
status: draft
---
```
## Research Phase (do this first, before writing)
### Step 1: Identify source articles
From the digest's news items, find the original source URLs. Never write from the digest summary alone — always read the originals.
### Step 2: Read each source article
Use this curl technique for most sites:
```bash
curl -sL --max-time 20 "<URL>" | python3 -c "
import sys, re
html = sys.stdin.read()
# Strip scripts and styles
html = re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL)
html = re.sub(r'<style[^>]*>.*?</style>', '', html, flags=re.DOTALL)
# Try to get <article> content first
match = re.search(r'<article[^>]*>(.*?)</article>', html, re.DOTALL)
if match:
text = re.sub(r'<[^>]+>', ' ', match.group(1))
else:
text = re.sub(r'<[^>]+>', ' ', html)
text = re.sub(r'\s+', ' ', text).strip()
print(text[:15000])
"
```
For Cloudflare-protected sites (e.g. VentureBeat):
- Fall back to `browser_navigate``browser_snapshot(full=true)``browser_scroll` as needed
### Step 3: Extract key data per source
For each source, extract:
- **Numbers** — all specific metrics, percentages, dollar amounts
- **Quotes** — direct statements from researchers/executives
- **Mechanisms** — how something works (the causal chain)
- **Contrasts** — before/after, old/new, claimed vs actual
### Step 4: Synthesize across sources
Organize findings into a coherent narrative:
1. What's the core insight/problem each article describes?
2. How do the sources overlap, complement, or contradict each other?
3. What's the single actionable takeaway that readers can use today?
## Writing Phase
### Thai Content Structure (per article)
```
# [Hook-driven title]
> [Hook paragraph — 1-2 sentences, breaks reader expectation]
## 📚 สารบัญ
- [Section 1]
- [Section 2]
- ...
## [Section 1 — Core insight]
[Data table with comparison columns]
[Explanation paragraph — 2-4 sentences]
📌 [Topic] Takeaway: [Actionable insight in 1-2 sentences]
## [Section 2 — Mechanism]
[Data table with before/after]
[Explanation]
📌 [Topic] Takeaway: [...]
...
## สรุป Actionable Takeaways
| สิ่งที่ต้องทำ | เหตุผล |
|:---|:---|
| ✅ [Action] | [Why — bulletproof reasoning] |
| ❌ [Avoid] | [Why — the trap to dodge] |
---
**ที่มา:**
- [Author], "[Title]" — [Publication], [Date]
```
### Thai Writing Conventions
| Element | Convention |
|:---|:---|
| **Title** | Hook-driven ≤ 60 chars. Curiosity gap or contrarian claim. Include target keyword naturally |
| **Opening** | Break expectation — "ถ้าคุณคิดว่า X — คุณคิดผิด" / "ไม่ใช่แค่ X — มันคือ Y" |
| **Section labels** | 📌 "GEO Takeaway" / "Content Strategy Takeaway" / "Business Takeaway" |
| **Tables** | Comparison columns with emoji indicators (✅ ❌ 🟢 🟡 🔴 🏆) |
| **Code/terms** | Use backticks for English technical terms (`result_source`, `turn_use_case`) |
| **Numbers** | Bold the headline number — "เร่งความเร็วได้ **85%**" |
| **Sources footer** | "**ที่มา:**" section listing all source articles as markdown links |
### Avoid
- Generic openings: "ในโลกดิจิทัลวันนี้", "ด้วยความก้าวหน้าของเทคโนโลยี"
- Artificial FAQ sections — don't add them unless the content genuinely raises questions
- Keyword stuffing — use Thai synonyms naturally
- Over-explaining — trust the reader to connect simple dots
## Pitfalls
1. **web_extract / web_search may not be configured** — always have curl+browser fallback ready. Script/security warnings from pipe-to-python are a real risk; get auto-approval or use inline parsing.
2. **Majority of articles are in the 60_Articles/<slug>/article.md format** — check existing structure before saving. Never invent a new format.
3. **Source article may be behind paywall or bot-block** — curl can't read everything. Browser tools handle Cloudflare/Vercel. YouTube and social platforms need different approaches.
4. **Content date ≠ publish date** — use the source research date or the article's original publication date, not today's date, for the article slug and frontmatter.
5. **Multiple articles from one digest session** — batch them in parallel via delegate_task if independent; write sequentially if they share data.
6. **arXiv API returns Atom XML, not RSS** — parse `<entry>` elements specifically; the `head -300` approach in the newsletter skill truncates at a fixed line count, so use `python3 -c` for proper XML parsing.

View File

@@ -0,0 +1,197 @@
---
name: orbites-ai-products
description: Curate AI product launches AND trending GitHub repositories. From Product Hunt, Hacker News, GitHub Trending, Techmeme. For OrbitOS. Use when user says 'AI products', 'product launches', 'new AI tools', 'trending repos', 'GitHub trending', 'สินค้า AI ใหม่'.
---
# OrbitOS: Product Launches & GitHub Trending
Fetch, deduplicate, and rank AI product launches AND trending GitHub repositories into a daily digest.
## Sources
### 🚀 AI Product Launches
| Source | URL | Method |
|--------|-----|--------|
| Product Hunt | `https://www.producthunt.com/feed` | web_extract (filter AI) |
| Hacker News Show HN | `https://hn.algolia.com/api/v1/search?tags=show_hn&numericFilters=created_at_i>TIMESTAMP` | web_extract (24h window) |
| Techmeme | `https://techmeme.com/river` | web_extract |
### ⭐ GitHub Trending (All Languages)
| Source | URL | Method |
|--------|-----|--------|
| GitHub Trending (daily) | `https://github.com/trending?since=daily` | web_extract |
| GitHub Trending (weekly) | `https://github.com/trending?since=weekly` | web_extract |
| GitHub API (recent stars) | `https://api.github.com/search/repositories?q=created:>YYYY-MM-DD&sort=stars&order=desc&per_page=25` | web_extract |
## Workflow
1. **Check cache**: Look for `50_Resources/ProductLaunches/YYYY-MM/YYYY-MM-DD-Digest.md` (relative to vault root). Return cached if exists for today.
2. **Fetch AI product sources** (see Provider Fallbacks for exact commands):
- Product Hunt: `curl` the Atom RSS — filter items with AI/ML/LLM keywords from titles/descriptions
- HN Show HN: `curl` the JSON API with timestamp = 24h ago Unix time — filter AI-related
- Techmeme: Skip if browser unavailable (HTML-only); otherwise use browser tools
3. **Fetch GitHub trending**:
- GitHub API: `curl` the JSON search endpoint — parse for repo name, stars, language, description
- GitHub Trending pages: Skip if browser unavailable (HTML-only SPA); otherwise use browser tools
- Merge results, deduplicate
4. **Classify every item**:
- `ai-product` — AI/ML/LLM tools, models, agents, AI-native SaaS
- `dev-tool` — developer tools, frameworks, libraries, CLI tools
- `open-source` — notable OSS repos (any language)
- `productivity` — automation, workflow, no-code/low-code tools
5. **Deduplicate**: Same product/repo across sources → merge, keep best description, combine metrics (stars, votes, points).
6. **Rank within each category**:
- For AI products: engagement (PH votes/500, HN points/100) + content potential + novelty
- For repos: stars (recent velocity) + content potential (tutorial-friendly, review-worthy) + OSS bonus
7. **Generate digest** — bilingual Thai/English:
```markdown
# 🚀 Product & Repo Digest — YYYY-MM-DD
## 🚀 AI Product Launches — Top 5
- **[Product Name]** — 1-line description. [PH ▲N / HN N pts]
*Angle:* content idea in Thai
## ⭐ GitHub Trending — Top 5
- **[repo/name]** (⭐ N this week, 🗣️ Language)
> One-line description
*Angle:* tutorial / review / deep dive
## 🛠️ Developer Tools
- ...
## 📦 Open Source Highlights
- ...
## 💡 Content Creation Opportunities
Top 5 across all categories:
1. ...
```
8. **Save files** (relative to vault root):
- `50_Resources/ProductLaunches/YYYY-MM/YYYY-MM-DD-Digest.md`
- Raw dumps in `50_Resources/ProductLaunches/YYYY-MM/Raw/` if substantial
## Output Format
**Manual invocation**: Full digest with all sections.
**From start-my-day cron**: Condensed:
```
**🚀 Products & Repos:**
🚀 AI: [N launches] — top product
⭐ GitHub: [N repos] — top repo
Full digest: [[YYYY-MM-DD-Digest]]
```
## Content Angle Logic
For AI products:
- High engagement + tutorial-friendly → "Tutorial opportunity"
- Novel + early stage → "First-mover advantage"
- Open source + complex → "Deep dive analysis"
- SaaS + practical → "Tool review"
- Similar to existing → "Comparison vs [competitor]"
For GitHub repos:
- High star velocity + tutorial-friendly → "Quick start guide"
- Novel approach/tech → "What's new in [language/domain]"
- Developer tooling → "Productivity boost review"
- Academic paper repo → "Paper walkthrough"
- Framework/library → "Build with [repo] tutorial"
## Provider Fallbacks
`web_extract` may be unavailable. **Primary approach is `curl` via terminal.** Only use `web_extract` if it returns data.
### Fetch commands (preferred — curl + terminal)
```bash
# Product Hunt RSS (Atom feed — works with curl!)
# macOS: grep -oP (Perl regex) NOT available. Use python3 for structured parsing instead:
curl -sL --max-time 15 "https://www.producthunt.com/feed" | python3 -c "
import sys, re
raw = sys.stdin.read()
entries = re.findall(r'<entry>.*?<title>(.*?)</title>.*?<link.*?href=\"(.*?)\".*?<content.*?>(.*?)</content>', raw, re.DOTALL)
for t,l,c in entries[:20]:
c_clean = re.sub(r'<[^>]+>', '', c)[:150]
ai_kw = ['ai','ml','llm','gpt','neural','intelligence','agent','chat','compute','model','deep','learning']
is_ai = any(kw in t.lower() or kw in c_clean.lower() for kw in ai_kw)
tag = '[AI]' if is_ai else '[ ]'
print(f'{tag} {t.strip()}')
print(f' {c_clean}')
print()
"
# ⚠️ NOTE: First <link> in the Atom feed is the feed URL itself, not a product.
# Product page URLs start from the second <link> entry (off-by-one vs titles).
# HN Show HN (JSON API — parse with python3)
# TIMESTAMP = 48h ago Unix time (wider window for weekend backfill)
# ⚠️ CRITICAL: The `>` in `created_at_i>` MUST be URL-encoded as `%3E`.
# The literal `>` character causes Algolia to return 400 Bad Request.
# Always use %3E in the numericFilters parameter:
curl -sL --max-time 15 "https://hn.algolia.com/api/v1/search?tags=show_hn&numericFilters=created_at_i%3E1782061200&hitsPerPage=20" | python3 -c "
import sys,json
raw = sys.stdin.read()
try:
d = json.loads(raw)
print(f'Total hits: {d.get(\"nbHits\",0)}')
for h in d.get('hits',[])[:15]:
title = h.get('title','')
pts = h.get('points',0) or 0
url = h.get('url','') or ''
print(f'{title} | {pts} pts | {url}')
except Exception as e:
print(f'Error: {e}')
"
# Techmeme (HTML-only — needs browser for structured extraction)
# Fallback: skip if browser tools unavailable
# URL: https://techmeme.com/river
# GitHub Trending (HTML-only — needs browser for structured extraction)
# Fallback: skip if browser tools unavailable
# URL: https://github.com/trending?since=daily
# GitHub API (JSON — parse with python3)
# ⚠️ Same %3E encoding needed for `created:>` filter
curl -sL --max-time 15 "https://api.github.com/search/repositories?q=created:%3E2026-06-22&sort=stars&order=desc&per_page=20" | python3 -c "
import sys,json
d=json.load(sys.stdin)
for r in d.get('items',[])[:15]:
print(f'{r[\"full_name\"]} | ⭐{r[\"stargazers_count\"]} | 🗣️{r.get(\"language\",\"N/A\")} | {r[\"description\"] or \"N/A\"}')
"
## Source Health Notes
| Source | Status | Note |
|--------|--------|------|
| Product Hunt RSS | ✅ Active | Atom feed at `producthunt.com/feed` — works with curl. ⚠️ First `<link>` is feed URL, product links start at offset 1. See `references/product-hunt-atom-parsing.md` for full structure. |
| HN Show HN API | ✅ Active | JSON API at `hn.algolia.com`. ⚠️ **Must URL-encode `>` as `%3E`** in `numericFilters` or returns 400. See `references/hn-algolia-api.md` for details. |
| Techmeme River | ⚠️ HTML-only | Returns full HTML page, not parseable with curl. Needs browser or skip. |
| GitHub Trending | ⚠️ HTML-only | Returns full React SPA HTML, not parseable with curl. **Use GitHub Search API instead.** |
| GitHub Search API | ✅ Active | JSON API — `api.github.com/search/repositories` works with curl. ⚠️ Same `>` → `%3E` encoding needed in `created:>` filter. |
## Cron Mode Constraints
- **`execute_code` is BLOCKED in cron mode.** Use individual `terminal` calls. Batch parallel `curl` fetches.
- **`web_extract` may be unavailable.** Fall back to `curl` for Product Hunt RSS and HN API; skip Techmeme/GitHub Trending (HTML-only) or use browser tools if available.
- **Product Hunt RSS via curl returns Atom XML** — filter for AI/ML keywords manually. macOS `grep -oP` does NOT exist; use `python3 -c` for parsing (see Provider Fallbacks).
- **HN Algolia API** — always URL-encode `>` as `%3E` in `numericFilters` or the API returns 400.
- **GitHub API** — same `%3E` encoding needed for `created:>` in the `q` parameter.
## Error Handling
- Product Hunt blocked: Skip, use HN + Techmeme
- GitHub rate-limited: Use trending page HTML only (no API)
- All AI product sources down: Still deliver GitHub trending section
- Empty results: Create minimal digest noting "No new items today"
- Techmeme/GitHub HTML-only (no browser): Note "⚠️ Unavailable (HTML-only, no browser)" and skip gracefully
- HN API returns 400: Check that `>` in `numericFilters` is URL-encoded as `%3E`
- HN API returns empty: Widen the timestamp window to 48h
- Product Hunt link mapping off: First `<link>` in Atom feed is feed URL, not product. Use `python3` regex to map titles to links at correct offsets.

View File

@@ -0,0 +1,63 @@
# HN Algolia API — Query Reference
## Endpoint
```
GET https://hn.algolia.com/api/v1/search
```
## Critical: URL-Encoding `>` in `numericFilters`
The `numericFilters` parameter uses expressions like `created_at_i>TIMESTAMP`.
**The `>` MUST be URL-encoded as `%3E`.** Passing a literal `>` in the curl URL causes Algolia to return `400 Bad Request`.
### ❌ Wrong — returns 400
```bash
curl "https://hn.algolia.com/api/v1/search?tags=show_hn&numericFilters=created_at_i>1782061200"
```
### ✅ Correct — works
```bash
curl "https://hn.algolia.com/api/v1/search?tags=show_hn&numericFilters=created_at_i%3E1782061200"
```
## Pagination
Add `&hitsPerPage=N` (max 1000). Default is 20.
## Filter Tags
| Tag | Description |
|-----|-------------|
| `show_hn` | Show HN posts |
| `ask_hn` | Ask HN posts |
| `story` | All stories |
| `comment` | All comments |
| `front_page` | Stories on the front page |
## Timestamp Calculation
macOS: `date -j -f "%Y-%m-%d %H:%M:%S" "2026-06-29 00:00:00" "+%s"`
For 48h window: subtract 172800 from the result.
## Working Curl Command
```bash
curl -sL --max-time 15 \
"https://hn.algolia.com/api/v1/search?tags=show_hn&numericFilters=created_at_i%3ETIMESTAMP&hitsPerPage=20" \
| python3 -c "
import sys,json
raw = sys.stdin.read()
try:
d = json.loads(raw)
print(f'Total hits: {d.get(\"nbHits\",0)}')
for h in d.get('hits',[])[:15]:
title = h.get('title','')
pts = h.get('points',0) or 0
url = h.get('url','') or ''
print(f'{title} | {pts} pts | {url}')
except: print('Parse error')
"
```

View File

@@ -0,0 +1,58 @@
# Product Hunt Atom XML — Parsing Reference
## Feed Format
Product Hunt uses **Atom XML** (`<feed>` root, not RSS `<rss>`).
## Element Structure
```xml
<feed>
<title>Product Hunt</title>
<link href="https://www.producthunt.com/feed"/> <!-- feed URL — NOT a product -->
<entry>
<title>Product Name</title>
<link href="https://www.producthunt.com/products/product-slug"/> <!-- product page -->
<content type="html">&lt;p&gt;Description here&lt;/p&gt;</content>
</entry>
</feed>
```
## Critical Quirks
### 1. First `<link>` is the feed URL
The very first `<link href="...">` after `<feed>` is `https://www.producthunt.com/feed`**not a product link**. Product links start from the second `<link>` entry.
When using `re.findall(r'<entry>.*?<title>(.*?)</title>.*?<link.*?href="(.*?)".*?<content.*?>(.*?)</content>', ...)`, each entry's link is its product page URL. But if you extract ALL `<link>` elements globally and pair by index with titles, account for the off-by-one: `titles[i]` maps to `links[i+1]` (because `links[0]` is the feed URL).
### 2. macOS: No `grep -oP`
macOS grep does NOT support `-P` (Perl regex). Use `python3` for structured extraction instead.
### 3. AI Product Detection
Filter with keywords: `ai`, `ml`, `llm`, `gpt`, `neural`, `intelligence`, `agent`, `chat`, `compute`, `model`, `deep`, `learning`
Check BOTH title AND description (content).
### 4. Content HTML Encoding
`<content type="html">` contains HTML-encoded content with `<p>`, `<a>` tags. Strip tags with `re.sub(r'<[^>]+>', '', text)`.
## Working Python3 Extraction
```python
import sys, re
raw = sys.stdin.read()
entries = re.findall(
r'<entry>.*?<title>(.*?)</title>.*?'
r'<link.*?href="(.*?)".*?'
r'<content.*?>(.*?)</content>',
raw, re.DOTALL
)
for title, link, content in entries[:20]:
desc = re.sub(r'<[^>]+>', '', content)[:150]
is_ai = any(kw in title.lower() or kw in desc.lower()
for kw in ['ai','ml','llm','gpt','neural',
'intelligence','agent','chat',
'compute','model','deep'])
tag = '[AI]' if is_ai else '[ ]'
print(f'{tag} {title.strip()}')
print(f' {desc}')
```

View File

@@ -0,0 +1,74 @@
---
name: orbites-archive
description: Archive completed projects and processed inbox items in OrbitOS. Use when user says 'archive', 'clean up', 'file this', 'เก็บเข้าคลัง', 'clean completed'.
---
# OrbitOS: Archive — Clean Up Completed Items
You are the Vault Archivist for OrbitOS. Archive completed work while preserving historical context.
## Step 1: Find Items to Archive
1. **Completed projects:** Search `20_Project/` for notes with `status: done`
2. **Processed inbox:** Search `00_Inbox/` for files with `status: processed` in frontmatter
Present findings:
```markdown
## Items Ready for Archive
**Completed Projects ([N]):**
- [[Project1]] - Completed on [date]
**Processed Inbox Items ([N]):**
- Idea about X - Processed to [[ProjectName]]
Would you like to:
1. Archive all
2. Archive projects only
3. Archive inbox only
4. Select specific items
```
## Step 2: Archive Process
For each project:
1. **Read the project file(s)** — get full content and metadata
2. **Move to archives:**
- Single file: `99_System/Archives/Projects/YYYY/ProjectName.md`
- Folder: `99_System/Archives/Projects/YYYY/ProjectName/`
3. **Update metadata:** Add `archived: YYYY-MM-DD` to frontmatter
4. **Log:** Update today's daily note with archive action
For inbox items:
1. **Move to:** `99_System/Archives/Inbox/YYYY/MM/filename.md`
2. Organize by year and month of processing
3. Preserve all metadata
## Step 3: Summary Report
```markdown
## Archive Complete
**Archived [N] projects:**
- [[Project1]] → Archives/Projects/2026/Project1/
**Archived [N] inbox items:**
- idea.md → Archives/Inbox/2026/01/
**Vault Status:**
- Active projects: [N]
- Inbox items: [N]
**Recommendations:**
- [ ] Review on-hold projects
- [ ] Process remaining inbox items
```
## Important Rules
- **Preserve all content** — never delete, only move
- **Organize by year** — based on completion date
- **Update frontmatter** — add archived date
- **Confirm before archiving** — let user review first
- **Maintain links** — Obsidian wikilinks work across locations
- **Log the action** — update today's daily note

View File

@@ -0,0 +1,41 @@
---
name: orbites-ask
description: Quick answers to questions without heavy note-taking. For OrbitOS. Use when user says 'ask [question]', 'help me with', 'what is', 'ถาม', 'ช่วยอธิบาย'.
---
# OrbitOS: Ask — Quick Answers
You are a Knowledge Assistant for OrbitOS. Provide direct, helpful answers efficiently.
## Workflow
1. **Check vault first** (optional, if relevant):
- Quick search of `30_Research/` and `40_Wiki/` for existing knowledge
- If found, reference it with `[[NoteName]]`
2. **Answer directly**:
- Clear, concise answer in the conversation
- Code examples if helpful
- Link to existing vault notes with `[[NoteName]]`
3. **Optional: Save to vault** (only if substantive):
- If the answer contains reusable knowledge:
- Create wiki note: `40_Wiki/<Category>/<Concept>.md`
- Use template `99_System/Templates/Wiki_Template.md`
- Don't create notes for trivial Q&A
## Response Format
```
[Direct answer to question]
[Code example if applicable]
[Link to existing note: See [[ExistingNote]] for more]
```
## Do NOT
- Create plan files for simple questions
- Spawn sub-agents for quick lookups
- Over-engineer the response
- Create notes unless knowledge is genuinely reusable

View File

@@ -0,0 +1,77 @@
---
name: orbites-brainstorm
description: Interactive brainstorming session with OrbitOS. Explore ideas, then save as project or knowledge. Use when user says 'brainstorm', 'ideas', 'think about', 'ระดมสมอง'.
---
# OrbitOS: Brainstorm — Interactive Idea Exploration
You are the Brainstorming Facilitator for OrbitOS. Engage in an interactive, exploratory conversation to develop and refine ideas.
## Phase 1: Brainstorming Mode
### Your Role
- **Ask probing questions** to deepen understanding
- **Challenge assumptions** constructively
- **Explore multiple angles**: technical, practical, creative, strategic
- **Build on ideas** by suggesting variations
- **Identify connections** to existing vault knowledge
### Techniques
- **5 Whys**: Dig deeper into motivations
- **What if?**: Explore alternative scenarios
- **Devil's Advocate**: Challenge to strengthen
- **Analogies**: Draw parallels
- **Constraints**: "What if unlimited resources?" or "What if only 1 week?"
### Conversation Flow
1. **Start with context**: "What sparked this idea?", "What problem are you solving?"
2. **Explore deeply**: Ask follow-ups, let ideas breathe
3. **Capture insights**: Key concepts, actionable ideas, open questions
4. **Check vault context**: Search `20_Project/`, `30_Research/`, `40_Wiki/` for connections
### Tone
Curious, energetic, supportive but challenging, creative.
## Phase 2: Synthesis
When user signals they're ready (or after natural conclusion):
```markdown
## Brainstorming Summary
### Core Idea
[One-paragraph synthesis]
### Key Insights
1. [Insight 1]
### Potential Directions
- [Direction A]: [Description]
### Open Questions
- [Question 1]
### Connections to Existing Knowledge
- [[ExistingNote1]] - How it relates
```
## Phase 3: Action
Offer user three options via `clarify`:
1. **Create a Project** — use `orbites-kickoff` skill
2. **Capture Knowledge** — create research + wiki notes
3. **Keep Exploring** — save as inbox note, continue later
### Option 1: Create Project
Spawn a kickoff subagent with the brainstorming summary as input.
### Option 2: Capture Knowledge
Create main note at `30_Research/<Area>/<Topic>/<Topic>.md` + atomic wiki notes at `40_Wiki/<Category>/<Concept>.md`.
### Option 3: Keep Exploring
Create inbox note: `00_Inbox/Brainstorm_YYYY-MM-DD_<Topic>.md` for later processing.
## Important
- **Stay in conversation mode** — don't jump to creating files
- **Don't over-engineer** — this is exploration, not execution
- **Reference vault when helpful** — but don't interrupt flow

View File

@@ -0,0 +1,121 @@
---
name: orbites-end-my-day
description: Evening wrap-up for OrbitOS — review today's sessions, check Gitea git commits, update daily note with progress. Use when user says 'end my day', 'evening wrap-up', 'สรุปวัน', 'ปิดงาน'.
---
# OrbitOS: End My Day — Evening Wrap-Up
You are the Evening Archivist for OrbitOS. At ~21:00, wrap up the day by reviewing what happened and updating the daily note.
## Vault & Gitea Convention
- **Vault** (`~/vault/`): metadata — daily notes, project concepts, progress notes (no source code)
- **Gitea** (`~/Gitea/`): source code repos with `.git` — separate remote origins
## Workflow
### Step 1: Gather Context
1. **Read today's daily note** at `10_Daily/YYYY-MM-DD.md`
- Note what was planned this morning
- What priorities were set
2. **Search all Hermes sessions from today**
- Use `session_search` to find sessions that happened today
- Extract key: projects discussed, decisions made, code written
- Distinguish cron sessions from user-interactive sessions — label each in log
3.5 **Check digest files** (new — between git activity and plan comparison)
- Check `50_Resources/Newsletters/YYYY-MM/YYYY-MM-DD-Digest.md` — was the AI news digest generated?
- Check `50_Resources/ProductLaunches/YYYY-MM/YYYY-MM-DD-Digest.md` — was the product launch digest generated?
- Update the `## AI Digest` section in the daily note accordingly
- If neither exists, leave as-is (the morning cron may not have run)
3. **Check Gitea git activity**
- For each project in `~/Gitea/` with a `.git/` directory:
- `git log --since="YYYY-MM-DD 00:00" --until="YYYY-MM-DD 23:59" --oneline --format="%h %ai %s"`
- Count commits, note which repos were active, capture latest commit message
- For the **Git Activity table** in the daily note: rename the header to say "Today" not "Since Yesterday" (since morning note may still say "Since Yesterday")
- Skip projects without `.git/`
4. **Compare plan vs. reality**
- What was planned in the morning daily note?
- What actually got done (from sessions + git commits)?
### Step 2: Update Daily Note
Update `10_Daily/YYYY-MM-DD.md`:
```markdown
## Today's Summary
**Git Activity:**
| Project | Commits | Top commit |
|---------|---------|------------|
| moreminimore-astroreal | 3 | fix header alignment |
| CrowdSight | 0 | (no commits today) |
**Sessions:** [N] sessions today
- Discussed: [topics]
**Progress vs Plan:**
- ✅ Completed: [items from morning priorities]
- ⏳ In progress: [items still active]
- ❌ Not started: [items touched]
## Tomorrow's Focus
- [ ] Priority 1 (carryover)
- [ ] Priority 2
---
**Energy left:** ⚡⚡⚡ | **Focus:** 🎯🎯🎯
```
### Step 3: Flag Stale Projects
For each project in `~/Gitea/` with a `.git/` directory:
- Check `git log -1 --format="%ai"` — get the actual last commit date
- Calculate days since last commit vs today
- If no activity > 7 days → flag with `⚠️ stale` note (include exact days)
- For projects in vault's `20_Projects/` without a `.git/` in `~/Gitea/`:
- Check if the project even has a git repo anywhere
- If no git at all → suggest initializing git repo
### Step 4: Save & Present
```markdown
## 🌙 End of day wrap-up
**Today's note:** [[YYYY-MM-DD]] updated
**Git activity:** [N] commits across [M] projects
- [[ProjectName]] — [N] commits
**Plan vs reality:**
- ✅ [N] completed
- ⏳ [N] in progress
- ❌ [N] untouched
**Tomorrow's preview:**
- [ ] Top priority
- [ ] Carryover tasks
Have a good evening! 🌙
```
## Important Rules
- **Don't create a NEW daily note** — only UPDATE today's existing note
- **Respect existing content** — append/merge, don't overwrite
- **All times are local** — use system timezone
- **Skip sessions with no meaningful content** (just /help, /model etc.)
- **Be concise** — this is a wrap-up, not a full audit
- **Use Thai** for communication
## Edge Cases
- **No sessions today:** Note "No recorded sessions" — maybe work was outside Hermes
- **Daily note missing:** Create minimal note + warn user
- **Zero git commits:** Note it, but don't judge — planning/research days are valid
- **AI Digest section says ❌ when digests ran:** Check `50_Resources/Newsletters/` and `50_Resources/ProductLaunches/` for today's digest files. If they exist, update the section from ❌ to ✅
- **Git Activity header says "Since Yesterday":** The morning note's git table may say "Since Yesterday". Rename to "Today" in the evening update since we're now comparing today's activity
- **Cron at 21:00:** No user present — make reasonable assumptions, don't ask questions

View File

@@ -0,0 +1,62 @@
---
name: orbites-json-canvas
description: Create JSON Canvas files (.canvas) — visual mind maps, flowcharts, and boards for Obsidian. Use when working with .canvas files in OrbitOS.
---
# OrbitOS: JSON Canvas Reference
JSON Canvas is an open format for infinite canvas data (`.canvas` files). [Spec 1.0](https://jsoncanvas.org/spec/1.0/)
## Structure
```json
{
"nodes": [],
"edges": []
}
```
## Node Types
### Text
```json
{ "id": "unique-id", "type": "text", "x": 0, "y": 0, "width": 400, "height": 200, "text": "## Title\nMarkdown content" }
```
### File
```json
{ "id": "unique-id", "type": "file", "x": 500, "y": 0, "width": 400, "height": 300, "file": "Notes/Note.md", "subpath": "#Heading" }
```
### Link
```json
{ "id": "unique-id", "type": "link", "x": 1000, "y": 0, "width": 400, "height": 200, "url": "https://example.com" }
```
### Group
```json
{ "id": "unique-id", "type": "group", "x": -50, "y": -50, "width": 1000, "height": 600, "label": "Section", "color": "4" }
```
## Edges
```json
{
"id": "edge-id",
"fromNode": "node1-id",
"fromSide": "right",
"toNode": "node2-id",
"toSide": "left",
"toEnd": "arrow",
"color": "1",
"label": "leads to"
}
```
- Sides: `top`, `right`, `bottom`, `left`
- Ends: `none`, `arrow`
- Colors: `"1"`=Red, `"2"`=Orange, `"3"`=Yellow, `"4"`=Green, `"5"`=Cyan, `"6"`=Purple
- Also supports hex colors: `"#FF0000"`
## Z-Index
First node = bottom layer, last node = top layer.

View File

@@ -0,0 +1,122 @@
---
name: orbites-kickoff
description: Convert an idea or inbox note into a structured OrbitOS project with C.A.P. layout (Context, Actions, Progress). Creates the PLAN in 90_Plans/ (vault territory) — does NOT modify code inside project git repos. Use when user says 'kick off project', 'new project', 'create project', 'start project', 'สร้างโปรเจกต์ใหม่'.
---
# OrbitOS: Kickoff — Idea to Project
You are the Project Manager orchestrator for OrbitOS. Transform ideas into structured C.A.P. projects.
## Territory Boundaries (CRITICAL)
The OrbitOS vault has TWO kinds of content:
- **Vault territory** (90_Plans/, 10_Daily/, 00_Inbox/, 30_Research/, 40_Wiki/) — these are tracked by vault git. CREATE and MODIFY files here freely.
- **Project git repos** (20_Projects/CrowdSight/, 20_Projects/moreminimore/, etc.) — each has its own `.git/` and its own remote. Do NOT modify code inside these repos during a vault session. That belongs to a project session.
This skill operates in VAULT TERRITORY only: it creates a plan file in 90_Plans/, then optionally a project metadata note in 20_Projects/ describing the repo. It does NOT touch source code.
## Input Context
The user can provide input in three ways:
1. **File path**: e.g., "00_Inbox/MyIdea.md" — read the file
2. **Inline text**: e.g., "Build a habit tracker app"
3. **No input**: If nothing provided, list files from `00_Inbox/` and ask user to pick one
**Language Rule**: Match the user's language for all responses and generated files.
## Phase 1: Plan (Delegate to Subagent)
Spawn a planning subagent:
```python
context = f"""
Create a project kickoff plan for: [user's idea]
1. Search 10_Daily/ and 00_Inbox/ for existing notes related to this idea
2. Check 20_Projects/ to see if a git repo for this project already exists
3. Identify relevant Area (SoftwareEngineering, Finance, Health, etc.)
4. Create plan file at 90_Plans/Plan_YYYY-MM-DD_Kickoff_<ProjectName>.md:
# Kickoff Plan: [Project Name]
## Source
- [inbox file path or 'inline input']
## Objective
[One sentence summary]
## Proposed Action Items
[ ] Define success criteria
[ ] Break down into phases
[ ] Identify dependencies
[ ] Set up project structure
## Draft Project Outline
### Context
[What problem this solves]
### Actions (Phases)
- Phase 1: [Description]
- Phase 2: [Description]
### Success Metrics
- [ ] Metric 1
5. Return the plan file path.
"""
delegate_task(goal="Create project kickoff plan", context=context, toolsets=["terminal", "file"])
```
After the plan subagent returns, ask user to review with `clarify`:
"Plan created at `[path]`. Review and confirm to proceed?"
## Phase 2: Execute (After User Confirmation)
Spawn execution subagent:
```python
context = f"""
Execute project kickoff from plan at: 90_Plans/Plan_YYYY-MM-DD_Kickoff_<ProjectName>.md
1. Read the plan file, note any user modifications
2. Determine scope:
- If this is a NEW project (no existing git repo in 20_Projects/):
Create 20_Projects/<ProjectName>/<ProjectName>.md with C.A.P. metadata
- If this project already exists as a nested git repo (has .git/):
Create ONLY the metadata file 20_Projects/<ProjectName>.md describing goals
Do NOT modify any files inside the existing git repo
3. Use C.A.P. structure:
- **Context**: Objectives, background
- **Actions**: Phases with tasks
- **Progress**: Empty for future updates
4. Link project in today's daily note at 10_Daily/YYYY-MM-DD.md
5. Archive plan: move to 90_Plans/Archives/
6. If from inbox:
- Update inbox: set status: processed, archived: YYYY-MM-DD
- Move to 99_System/Archives/Inbox/YYYY/MM/
Project frontmatter:
---
title: "Project Name"
type: project
created: YYYY-MM-DD
status: active
area: "[[AreaName]]"
repo: "gitea-url or 'local-only'"
due:
priority: P2
tags: [project, ...]
---
"""
delegate_task(goal="Execute project kickoff", context=context, toolsets=["terminal", "file"])
```
Report back with:
- Path to the plan
- Path to project metadata (if created)
- Whether the project is new or already has an existing git repo
## Follow-up
If user asks for code-level changes:
- Say "That requires a project session — switch to 20_Projects/CrowdSight and I'll help there"
- Do NOT modify code in a nested git repo during a vault session

View File

@@ -0,0 +1,58 @@
---
name: orbites-obsidian-bases
description: Create and edit Obsidian Bases (.base files) — database-like views with filters, formulas, and summaries. Use when working with .base files in OrbitOS.
---
# OrbitOS: Obsidian Bases Reference
Obsidian Bases are YAML files (`*.base`) that define dynamic views of notes.
## Schema
```yaml
filters: # Global: single filter string, or and/or/not nesting
formulas: # Computed properties (e.g., days_old: "((now() - file.ctime) / 86400000).round(0)")
properties: # Display names
summaries: # Custom summary formulas
views: # Array of view definitions
- type: table|cards|list|map
name: "View Name"
filters: # View-specific filters
order: # Columns to display
groupBy: # Group settings
```
## Filter Syntax
```yaml
# Simple
filters: 'status == "done"'
# AND
filters:
and:
- 'status == "done"'
- 'priority > 3'
# OR, NOT, NESTED
filters:
or:
- file.hasTag("tag")
- and:
- file.hasTag("book")
- file.inFolder("Folder")
```
## Built-in Properties
- **File**: `file.name`, `file.basename`, `file.path`, `file.folder`, `file.ext`, `file.size`, `file.ctime`, `file.mtime`, `file.tags`, `file.links`, `file.backlinks`
- **Frontmatter**: Any frontmatter key (e.g., `status`, `priority`)
- **Formulas**: `formula.my_formula`
## Functions
- **Global**: `date()`, `now()`, `today()`, `if()`, `min()`, `max()`, `link()`
- **String**: `contains()`, `startsWith()`, `endsWith()`, `lower()`, `replace()`, `split()`
- **Number**: `abs()`, `ceil()`, `floor()`, `round()`, `toFixed()`
- **List**: `contains()`, `filter()`, `map()`, `reduce()`, `join()`, `sort()`, `unique()`
- **File**: `hasLink()`, `hasTag()`, `hasProperty()`, `inFolder()`
- **Date**: `format()`, `relative()`, arithmetic with durations

View File

@@ -0,0 +1,118 @@
---
name: orbites-start-my-day
description: Morning planning workflow for OrbitOS — review yesterday, scan inbox, create daily note with priorities. Use when user says 'start my day', 'morning routine', 'เริ่มวันใหม่', or 'good morning'.
---
# OrbitOS: Start My Day
You are the Daily Planner for OrbitOS. Create today's daily note with context from yesterday, active projects, and inbox.
## Vault Root
Default vault root: `~/vault/`. The vault IS a git repo. Use `search_files` and `read_file` to discover vault state. The vault structure is:
```
00_Inbox/ — Quick captures
10_Daily/ — Daily logs (YYYY-MM-DD.md)
20_Projects/ — Active projects — each is ITS OWN git repo with separate remote
Each subfolder (CrowdSight, moreminimore...) has `/.git/` inside.
DO NOT track or modify project-internal files via vault git.
Project git belongs to a PROJECT session, not this vault session.
30_Research/ — Reference notes
40_Wiki/ — Atomic concepts
50_Resources/ — Newsletters, ProductLaunches
90_Plans/ — Execution plans (vault-only territory)
99_System/ — Templates, Prompts, Archives
```
### Nested Git Repos (CRITICAL)
`20_Projects/CrowdSight/.git/` is a SEPARATE repo. `20_Projects/moreminimore/.git/` is a SEPARATE repo. Git itself handles this: running `git add .` at vault root skips any directory with a `.git` inside automatically.
**What this means for this skill:**
- **Vault git = plans, daily notes, wiki, inbox.** Push these up to the vault remote.
- **Project git = source code.** Do NOT run `git` commands inside a project folder during a vault session — that belongs to a project session.
- Project status ("last updated") should be read via `cd ~/vault/20_Projects/<name> && git log --oneline -1` — NOT by scanning markdown frontmatter.
- When you find stale projects (3+ days no update), check the git log timestamp, not the markdown file mtime.
## Workflow
### Step 1: Gather Context (Silent — do these in parallel)
1. **Get today's date** — use `YYYY-MM-DD` format
2. **Read yesterday's daily note** at `10_Daily/[yesterday].md`
- Extract incomplete tasks (unchecked `- [ ]` items)
3. **Find active projects** — scan `20_Projects/` for directories with `.git/` inside
- Each is a nested git repo. Check its status via `git log --oneline -1`
- Note: current commit, last update date, stale (3+ days no commit)
4. **Check inbox** — list files in `00_Inbox/` with `status: pending` (or no status)
- Count items waiting to be processed
### Step 2: Ask User for Input
Use the `clarify` tool to ask:
**Q1:** "What's your main focus today?"
- Offer options based on active projects + "Something else"
**Q2:** "Any new ideas or tasks on your mind?"
- Free text
**Q3:** "Any blockers or concerns?"
- Free text
### Step 3: Create Today's Daily Note
1. **Check if today's note exists** at `10_Daily/YYYY-MM-DD.md`
- If exists: read and update (preserve existing content)
- If not: create from template `99_System/Templates/Daily_Note.md`
2. **Populate the daily note:**
- **Priorities**: Carryover incomplete tasks from yesterday → user's focus → project next actions
- **Log**: Leave empty for user
- **Notes**: Recommendations (time-sensitive items, stale projects, inbox count)
- **Related Projects**: List active projects with git status (last commit date, branch)
### Step 4: Process New Ideas
For each new idea from Q2:
1. Check if it already exists in projects or inbox
2. If new, create `00_Inbox/[Brief-Title].md` with frontmatter
### Step 5: Present Summary
```markdown
## Good morning! Your day is ready.
**Today's note:** [[YYYY-MM-DD]]
**Priorities:**
- [ ] Priority 1
**Active projects ([N]):**
- [[CrowdSight]] — last commit: 2 days ago
- [[moreminimore]] — stale ⚠️ 5 days
**New ideas captured ([N]):**
- [[Idea1]]
**Inbox:** [N] items waiting
```
## Important Rules
- **Always read yesterday's note** — don't assume it's empty
- **Flag stale projects** — no git commit in 3+ days (check via git log, not file mtime)
- **Carryover incomplete tasks** — unchecked items from yesterday
- **Don't overwrite** — if today's note exists, update it carefully
- **Link everything** — wikilinks `[[NoteName]]`
- **Do NOT touch code inside project git repos** — they belong to project sessions
## Edge Cases
- **No active projects:** Suggest processing inbox or starting something new
- **No yesterday's note:** Skip carryover, start fresh
- **Today's note already exists:** Read it, merge priorities, don't duplicate
- **Nested repo has no commits yet:** Note as "new project, not yet initialized"

View File

@@ -0,0 +1,162 @@
---
name: orbites-vault-git
description: Git operations for OrbitOS vault — init, push large repos with many files, .gitignore for monorepo, HTTP 413 workarounds, project deploy separation. Use when setting up, pushing, or troubleshooting the OrbitOS vault git repo.
---
# OrbitOS: Vault Git Management
## Architecture — Single Vault Repo + Separate Deploy Repos
The OrbitOS vault is a **single git monorepo** that tracks EVERYTHING — metadata (inbox, daily, wiki, plans) AND all project source code, images, CSVs, PDFs, documents. Clone once and you have the complete workspace.
```
~/vault/ ← Git repo A (vault — everything)
├── .gitignore ← Build artifacts only
├── 00_Inbox/
├── 10_Daily/
├── 20_Projects/
│ ├── CrowdSight/ ← tracked by vault git
│ ├── OrbitOS/
│ ├── moreminimore/
│ └── ... (all 10 projects)
├── 90_Plans/
└── 99_System/
```
Project repos in `~/Gitea/` remain separate for **deploy-only pushes**:
```
~/Gitea/MiroFish/.git/ ← Git repo B (deploy — CrowdSight)
~/Gitea/moreminimore-service-system/ ← Git repo C (deploy — moreminimore)
```
## Vault .gitignore — Build Artifacts ONLY
The `.gitignore` must exclude **only build artifacts**. NEVER exclude source files, images, PDFs, CSVs, or data files — the vault is a complete snapshot.
```gitignore
# Python build
__pycache__/
*.py[cod]
*$py.class
*.so
.env
.venv/
venv/
*.egg-info/
dist/
build/
# Node build
node_modules/
# OS
.DS_Store
Thumbs.db
# IDE
.idea/
.vscode/
*.swp
# AI agent state
.omc/
.hermes/
```
### DO NOT add:
```
*.csv ❌ — CSV data must be tracked
*.pdf ❌ — documents must be tracked
*.png *.jpg ❌ — images must be tracked
*.mq5 *.ex5 ❌ — MT5 sources must be tracked
20_Projects/*/ ❌ — projects must be tracked
```
## Init Vault Git
```bash
cd ~/vault
# Only if truly starting fresh:
rm -rf .git && git init
# Or use existing:
git init # if no .git yet
# First commit
git add .
git commit -m "init: vault — all projects + metadata"
git remote add origin https://git.moreminimore.com/kunthawat/vault.git
git push -u origin main --force
```
## HTTP 413 — Fixes in Priority Order
If `git push` fails with HTTP 413 ("Request Entity Too Large"):
### ① Increase buffer (first try):
```bash
git config http.postBuffer 524288000
git push
```
### ② Push in split chunks:
Commit one project or one file at a time, pushing each incrementally:
```bash
git add 20_Projects/CrowdSight/
git commit -m "add: CrowdSight data/assets"
git push
```
### ③ For very large repos, split per-file:
```bash
for f in $(git diff --cached --name-only); do
git add "$f" && git commit -m "add: $(basename "$f")" && git push
done
```
Expect ~600+ small commits — acceptable for initial setup. Optionally squash later with interactive rebase.
### ⚠️ Pitfall: False HTTP 413
`git push` may show HTTP 413 even when the push actually succeeded — the sideband connection closes before the client receives the success response. **Always verify** with:
```bash
git fetch origin
git log origin/main --oneline | head -3
```
### ④ DO NOT nuke `.git` and re-init:
`rm -rf .git && git init` destroys commit history and force-pushes can corrupt the remote. Only use this as a last resort when the local state is irrecoverable and no history matters.
## Project Deploy Workflow
**Vault** tracks all code changes. **Project repos** in ~/Gitea/ push only deploy-ready releases:
```bash
# Work normally in vault
cd ~/vault/20_Projects/CrowdSight
# edit code...
# Commit in vault (tracks everything)
cd ~/vault
git add . && git commit -m "feat: new simulation engine" && git push
# When ready for deploy — copy to project repo
cp -r ~/vault/20_Projects/CrowdSight/src/ ~/Gitea/MiroFish/
cd ~/Gitea/MiroFish
git add . && git commit -m "release: v2.1" && git push origin main
```
## Nested .git Handling
When copying projects from Gitea into vault:
1. **Remove** `20_Projects/<Project>/.git` from the vault copy — git creates gitlinks (mode 160000) otherwise
2. **Keep** the original `.git` in `~/Gitea/<Project>/` — used for deploy pushes only
3. Projects without `.git` in source (PreTradeChecklist, TPOsystem, grid-order-flow-mt5, moreminimore) are tracked as regular folders by vault git
## Verification Checklist
After pushing:
- [ ] `.gitignore` has build artifacts only (no `*.pdf`, `*.png`, `*.csv` patterns)
- [ ] `git ls-files | wc -l` shows ~2,000+ files including all images, CSVs, PDFs
- [ ] `git fetch origin && git diff origin/main` is empty
- [ ] `du -sh .git/` shows ~150-200MB (normal for full vault with assets)
- [ ] Project repos in `~/Gitea/` still have their `.git` for deploy pushes

View File

@@ -0,0 +1,93 @@
# HTTP 413 Resolution — Vault Git Push Failure
## Observed Problem
```
error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413
send-pack: unexpected disconnect while reading sideband packet
fatal: the remote end hung up unexpectedly
```
## Root Cause
The vault `.git/objects` pack file exceeded the Gitea server's payload size limit because it contained large binary assets alongside source code:
- Binary assets: `.png`, `.jpg`, `.jpeg`, `.pdf`, `.ico` (product images, screenshots, logos, price lists)
- Data files: `.csv`, `.csv.gz` (tick data, sample data)
- Agent state: `.omc/` directories with session checkpoints
Initial pack size: **175MB**
After splitting: **193MB** (all assets successfully pushed)
## Resolution Path (used in practice — June 2026)
### Key Insight: The user wants vault to track EVERYTHING
Do NOT add broad `.gitignore` patterns like `*.png`, `*.pdf`, `*.csv`. The vault is a complete snapshot — clone once and you have all files.
### Step 1 — Tighten .gitignore to build artifacts only
```gitignore
# Python build
__pycache__/
.venv/
venv/
*.egg-info/
dist/
build/
# Node build
node_modules/
# OS / IDE
.DS_Store
.idea/
.vscode/
# AI agent state
.omc/
.hermes/
```
REMOVE any broad patterns: `*.csv`, `*.pdf`, `*.png`, `*.jpg`, `*.mq5`, `20_Projects/*/`.
### Step 2 — Remove nested .git from project copies
Nested `.git` directories cause gitlinks (mode 160000) which break clone. Remove them before first commit:
```bash
for d in ~/vault/20_Projects/*/; do
[ -d "$d.git" ] && rm -rf "${d}.git"
done
```
### Step 3 — Split push per-file
When the vault has 200+ files of all types, push one file at a time:
```bash
for f in $(git diff --cached --name-only); do
git add "$f" && git commit -m "add: $(basename "$f")" && git push
done
```
This produces ~600 small commits — acceptable for initial setup. Can squash later.
### Step 4 — Verify despite false errors
`git push` may show HTTP 413 even when the push actually succeeded — the server accepts the pack but the sideband connection closes before the client receives the success response.
```bash
git fetch origin
git log origin/main --oneline | head -3
```
If the commit appears on origin, the push succeeded despite the error message.
## Prevention
- **Check size before push**: `du -sh .git/`
- **Increase post buffer**: `git config http.postBuffer 524288000`
- **Push incrementally** for initial full-vault upload
- **Never nuke .git**: `rm -rf .git && git init` destroys history — only use when local state is irrecoverable
- **Expected vault size**: 150-200MB (normal for complete workspace with assets)