OpenTIL
Capture and manage TIL (Today I Learned) entries on OpenTIL. Use /til <content> to capture, /til to extract insights from conversation, or /til list|publish|edit|search|delete|status|sync|tags|categories|batch to manage entries -- all without leaving the CLI.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install skilldb:biao29~tilcURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/skilldb%3Abiao29~til/file -o til.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/06c7e35e715508ef925cce23bad6d7cd4de4b76a# til
Capture and manage "Today I Learned" entries on OpenTIL -- from drafting to publishing, all within the CLI.
## Setup
1. Go to https://opentil.ai/dashboard/settings/tokens and create a Personal Access Token with `read:entries`, `write:entries`, and `delete:entries` scopes
2. Copy the token (starts with `til_`)
3. Set the environment variable:
```bash
export OPENTIL_TOKEN="til_xxx"
```
### Token Resolution
Token resolution order:
1. `$OPENTIL_TOKEN` environment variable (overrides all profiles)
2. `~/.til/credentials` file — active profile's token (created by `/til auth`)
If neither is set, entries are saved locally to `~/.til/drafts/`.
### Credential File Format
`~/.til/credentials` stores named profiles in YAML:
```yaml
active: personal
profiles:
personal:
token: til_abc...
nickname: hong
site_url: https://opentil.ai/@hong
host: https://opentil.ai
work:
token: til_xyz...
nickname: hong-corp
site_url: https://opentil.ai/@hong-corp
host: https://opentil.ai
```
- `active`: name of the currently active profile
- `profiles`: map of profile name → credentials
- Each profile stores: `token`, `nickname` (from API), `site_url`, `host`
**Backward compatibility**: If `~/.til/credentials` contains a plain text token (old format), silently migrate it to a `default` profile in YAML format and write back.
## Subcommand Routing
The first word after `/til` determines the action. Reserved words route to management subcommands; anything else is treated as content to capture.
| Invocation | Action |
|------------|--------|
| `/til list [drafts\|published\|all]` | List entries (default: drafts) |
| `/til publish [<id> \| last]` | Publish an entry |
| `/til unpublish <id>` | Unpublish (revert to draft) |
| `/til edit <id> [instructions]` | AI-assisted edit |
| `/til search <keyword>` | Search entries by title |
| `/til delete <id>` | Delete entry (with confirmation) |
| `/til status` | Show site status and connection info |
| `/til sync` | Sync local drafts to OpenTIL |
| `/til tags` | List site tags with usage counts |
| `/til categories` | List site categories |
| `/til batch <topics>` | Batch-capture multiple TIL entries |
| `/til auth` | Connect OpenTIL account (browser auth) |
| `/til auth switch [name]` | Switch active profile (by profile name or @nickname) |
| `/til auth list` | List all profiles |
| `/til auth remove <name>` | Remove a profile |
| `/til auth rename <old> <new>` | Rename a profile |
| `/til <anything else>` | Capture content as a new TIL |
| `/til` | Extract insights from conversation (multi-candidate) |
Reserved words: `list`, `publish`, `unpublish`, `edit`, `search`, `delete`, `status`, `sync`, `tags`, `categories`, `batch`, `auth`.
## Reference Loading
⚠️ DO NOT read reference files unless specified below. SKILL.md contains enough inline context for most operations.
### On subcommand dispatch (load before execution):
| Subcommand | References to load |
|------------|--------------------|
| `/til <content>` | none |
| `/til` (extract from conversation) | none |
| `/til list\|status\|tags\|categories` | [references/management.md](references/management.md) |
| `/til publish\|unpublish\|edit\|search\|delete\|batch` | [references/management.md](references/management.md) |
| `/til sync` | [references/management.md](references/management.md), [references/local-drafts.md](references/local-drafts.md) |
| `/til auth` | [references/management.md](references/management.md), [references/api.md](references/api.md) |
| `/til auth switch\|list\|remove\|rename` | [references/management.md](references/management.md) |
### On-demand (load only when the situation arises):
| Trigger | Reference to load |
|---------|-------------------|
| API returns non-2xx after inline error handling is insufficient | [references/api.md](references/api.md) |
| Auto-detection context (proactive TIL suggestion) | [references/auto-detection.md](references/auto-detection.md) |
| No token found (first-run local fallback) | [references/local-drafts.md](references/local-drafts.md) |
## API Quick Reference
**Create and publish an entry:**
```bash
curl -X POST "https://opentil.ai/api/v1/entries" \
-H "Authorization: Bearer $OPENTIL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entry": {
"title": "Go interfaces are satisfied implicitly",
"content": "In Go, a type implements an interface...",
"summary": "Go types implement interfaces implicitly by implementing their methods, with no explicit declaration needed.",
"tag_names": ["go", "interfaces"],
"published": true,
"lang": "en"
}
}'
```
**Key create parameters:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `content` | string | yes | Markdown body (max 100,000 chars) |
| `title` | string | no | Entry title (max 200 chars). Auto-generates slug. |
| `tag_names` | array | no | 1-3 lowercase tags, e.g. `["go", "concurrency"]` |
| `published` | boolean | no | `false` for draft (default), `true` to publish immediately |
| `lang` | string | no | Language code: `en`, `zh-CN`, `zh-TW`, `ja`, `ko`, etc. |
| `slug` | string | no | Custom URL slug. Auto-generated from title if omitted. |
| `visibility` | string | no | `public` (default), `unlisted`, or `private` |
| `summary` | string | no | AI-generated summary for listing pages (max 500 chars) |
**Management endpoints:**
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/entries?status=draft&q=keyword` | GET | List/search entries |
| `/entries/:id` | GET | Get a single entry |
| `/entries/:id` | PATCH | Update entry fields |
| `/entries/:id` | DELETE | Permanently delete entry |
| `/entries/:id/publish` | POST | Publish a draft |
| `/entries/:id/unpublish` | POST | Revert to draft |
| `/site` | GET | Site info (username, entry counts, etc.) |
| `/tags?sort=popular` | GET | List tags with usage counts |
| `/categories` | GET | List categories with entry counts |
> Full parameter list, response format, and error handling: see references/api.md
## Execution Flow
Every `/til` invocation follows this flow:
1. **Generate** -- craft the TIL entry (title, body, summary, tags, lang)
2. **Check token** -- resolve token (env var → active profile in `~/.til/credentials`)
- If `~/.til/credentials` exists in old plain-text format, migrate to YAML `default` profile first
- **Found** -> POST to API with `published: true` -> show published URL
- **Not found** -> save to `~/.til/drafts/` -> show first-run guide with connect prompt
- **401 response** -> save locally -> inline re-authentication (see Error Handling):
- Token from `~/.til/credentials` (active profile) or no prior token: prompt to reconnect via device flow → on success, update the active profile's token and auto-retry the original operation
- Token from `$OPENTIL_TOKEN` env var: cannot auto-fix — guide user to update/unset the variable
3. **Show identity** -- when ≥2 profiles are configured, include `Account: @nickname (profile_name)` in result messages so the user always knows which account was used
4. **Never lose content** -- the entry is always persisted somewhere
5. **On API failure** -> save locally as draft (fallback unchanged)
## `/til <content>` -- Explicit Capture
The user's input is **raw material** -- a seed, not the final entry. Generate a complete TIL from it:
- Short input (a sentence or phrase) -> expand into a full entry with context and examples
- Long input (a paragraph or more) -> refine and structure, but preserve the user's intent
**Steps:**
1. Treat the user's input as a seed -- craft a complete title + body from it
2. Generate a concise title (5-15 words) in the same language as the content
3. Write a self-contained Markdown body (see Content Guidelines below)
4. Generate a summary (see Summary Guidelines below)
5. Infer 1-3 lowercase tags from technical domain (e.g. `rails`, `postgresql`, `go`)
6. Detect la