devlog — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited devlog (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Maintain two local-only project files that work together:
| File | Role | Style |
|---|---|---|
DEVLOG.md | Chronological log of what was done, planned, and learned | Append-only, dated entries |
LESSON.md | Aggregated knowledge base of problems → root causes → solutions | Indexed, category-organized, reusable |
Rule of thumb: DEVLOG.md records the journey; LESSON.md records the wisdom.
Both files are local-only — they must never reach the remote repository, and the ignore rules for them must not be committed either. This is achieved with .git/info/exclude (a per-repo, never-tracked file), not .gitignore.
Invoke this skill when any of the following happen:
"做个总结", "加到 LESSON", "save a lesson", "remember this gotcha"
they are local.
On first invocation in a project (or if either file is missing):
templates and registers them in .git/info/exclude:
# POSIX (bash, zsh, Git Bash, WSL)
./.trae/skills/devlog/scripts/setup.sh # Windows PowerShell 5+
./.trae/skills/devlog/scripts/setup.ps1The script is idempotent — safe to re-run.
git check-ignore -v -- DEVLOG.md LESSON.md.git/info/exclude.If the files already exist, just read them for context and append. Never recreate. For background on the ignore choice, see references/git-exclude-explained.md.
Append-only chronological log.
## [YYYY-MM-DD] Brief title
**What:** One sentence describing what was done.
**Why:** The trigger, problem, or motivation.
**How:** Key implementation details (non-obvious only).
**Learned:** Gotchas, patterns, follow-ups, or open questions.Conventions:
YYYY-MM-DD.**Lesson:** see LESSON.md → <Category> → <slug>
DEVLOG.md (if present) for context and the ## Planned section.## Planned item matches the current task, note it in the upcoming entry.DEVLOG.md.## [YYYY-MM-DD] block under the existing content.## Planned into a dated entrywith a [Done] prefix in the title (do not delete the original line — strike it through or annotate it).
## Planned if any.LESSON.md if the learning is reusable (see below).DEVLOG-2026.md) and keepDEVLOG.md as an index.
Aggregated, searchable knowledge base of problems and their solutions. Where DEVLOG.md is a stream, LESSON.md is an index — each lesson is a stable entry that can be referenced, linked, and re-applied.
Promote a DEVLOG.md entry into LESSON.md when any of these is true:
out of context.
If the issue was trivial or one-off, keep it only in DEVLOG.md.
Group by category (one ## heading per category). Slugs are stable IDs you can link to.
## <Category, e.g. "Library / React">
### <YYYY-MM-DD> short-slug
- **Problem:** One-sentence description of the symptom.
- **Root cause:** Why it happened.
- **Solution:** The fix (commands, code, config).
- **How to avoid:** Checklist, lint rule, or convention to prevent recurrence.
- **Related:**
- `DEVLOG.md` → `## [YYYY-MM-DD] <title>`
- upstream issue / docs linkFor the canonical category list and naming rules, see references/categories.md.
Conventions:
Problem is the user-visible symptom. Root cause is the underlying reason.Keep them separate — symptoms recur even when causes change.
(e.g. push-fails-on-spaces-in-path).
most visible.
LESSON.md and pick (or create) the right category.DEVLOG.md entry(**Lesson:** see LESSON.md → <Category> → <slug>).
it instead of creating a duplicate — frequency matters.
LESSON.md before designing the approach.add a "Superseded by" note.
The following worked examples show what a good log entry looks like for common trigger scenarios. Match the shape (fields, terseness, cross-links) — the exact wording can vary.
User: "Add a /health endpoint that returns 200 if the DB is reachable."
Append to DEVLOG.md:
## [2026-06-19] Add /health endpoint with DB ping
**What:** Added GET /health that returns 200 with `{db: "ok"}` if the
PostgreSQL connection works, 503 otherwise.
**Why:** k8s liveness/readiness probes were killing the pod on transient
DB hiccups — they need a real signal, not just "process is up".
**How:** Used `pg.Pool.query('SELECT 1')` with a 1s timeout. Catches the
error and returns 503. No body on failure to keep probes cheap.
**Learned:** A common gotcha is to return 200 unconditionally after a
catch — that hides the very problem probes exist to detect.User: "Why did git push fail with 'Authentication failed' even though my token is in the credential helper?"
Append to DEVLOG.md:
## [2026-06-19] Fix GitHub push auth failure on Windows
**What:** Got `fatal: Authentication failed for https://github.com/...`
on every push despite `gh auth login` succeeding.
**Why:** `gh auth` writes the token to the GitHub CLI credential helper,
but `git push` was reading the system Git credential helper (no token
there). They don't share storage.
**How:** Configured the system helper to delegate to the GitHub CLI
helper: `git config --global credential.helper '!gh auth git-credential'`.
**Lesson:** see LESSON.md → Git → gh-auth-vs-git-credential-mismatch
**Learned:** `gh auth` ≠ git auth. Tools that wrap git often have their
own credential store.Then add to LESSON.md (top of the ## Git section):
## Git
### 2026-06-19 gh-auth-vs-git-credential-mismatch
- **Problem:** `git push` fails with auth error after `gh auth login`
succeeded on the same machine.
- **Root cause:** `gh auth` stores its token in its own credential
helper. Plain `git` uses whatever is configured in
`credential.helper` (often the system store or `manager-core` on
Windows). They don't share.
- **Solution:** Delegate the git credential helper to gh:
`git config --global credential.helper '!gh auth git-credential'`
- **How to avoid:** When you authenticate with `gh`, also re-run the
delegate command. Document this in the team onboarding README.
- **Related:**
- DEVLOG.md → ## [2026-06-19] Fix GitHub push auth failure on Windows
- https://cli.github.com/manual/gh_authUser: "Python's dict | dict merge sometimes loses keys, why?"
Append to DEVLOG.md:
## [2026-06-19] Python `|` dict merge: dict-of-dict gotcha
**What:** `a = {"x": {"a": 1}}; b = {"x": {"b": 2}}; merged = a | b`
gives `{"x": {"b": 2}}` — `a.x.a` is gone.
**Why:** PEP 584 `dict.__or__` replaces the *value* of each key, it does
not recurse. So nested dicts at the same key overwrite, not merge.
**How:** Use `{**a["x"], **b["x"]} | {"x": ...}` for the inner layer,
or `deepmerge` / `pydantic` for arbitrary depth.
**Lesson:** see LESSON.md → Language / Python → dict-or-merge-no-recurse
**Learned:** `|` looks like `dict.update` but is shallow; matches
`{**a, **b}` semantics, not `ChainMap`.Then add to LESSON.md (top of ## Language / Python):
## Language / Python
### 2026-06-19 dict-or-merge-no-recurse
- **Problem:** `a | b` for nested dicts silently drops keys.
- **Root cause:** `dict.__or__` is shallow — replaces values, doesn't
recurse into dicts.
- **Solution:** Use `{**a["k"], **b["k"]} | ...` per layer, or a deep
merge library (`deepmerge`, `pydantic`).
- **How to avoid:** In code review, flag any `|` on values that might
be dicts. Add a linter rule if your team uses dicts as config.
- **Related:**
- DEVLOG.md → ## [2026-06-19] Python `|` dict merge: dict-of-dict gotcha
- https://peps.python.org/pep-0584/Quick reference for picking a ## <Category> heading in LESSON.md. The full table with naming rules is in references/categories.md. Inline version is for quick decision-making at the moment of writing a new lesson; load the reference when you need naming details.
| Category | Use for |
|---|---|
Git | Branching, history, ignore rules, hooks, submodules |
Build | Bundlers, compilers, packaging |
CI | GitHub Actions, GitLab CI, test runners in CI |
Language / <name> | Per-language quirks (Language / Python, Language / TypeScript, ...) |
Library / <name> | Specific third-party libraries (Library / React, Library / FastAPI, ...) |
OS / Windows | PowerShell, paths, line endings |
OS / macOS | Gatekeeper, codesign, BSD vs GNU tools |
OS / Linux | Distros, package managers, systemd |
IDE / Trae | Trae IDE, MCP servers, custom skills |
Networking | DNS, HTTP, proxies, CORS, certificates |
Performance | Profiling, optimization, memory, latency |
Security | Auth, secrets, vulnerabilities, secure defaults |
Testing | Test frameworks, mocks, fixtures, coverage |
Debugging | strace, pdb, profilers, observability tools |
Trigger logic for choosing one:
Library / <name> orLanguage / <name>.
OS / <platform>.Build / CI / Testing.IDE / Trae.
Git / Networking / Performance / Security /Debugging — pick the closest.
Rule: prefer the closest existing category. Add a new one only after ~3 lessons accumulate that don't fit anywhere (see references/categories.md for the policy).
DEVLOG.md or LESSON.md to .gitignore — that pushes theignore rule to the remote, which the user explicitly does not want. Use .git/info/exclude. Consequence: teammates would inherit a rule that only protects your local notes.
no longer hide them. Recover with git rm --cached <file> and warn the user.
DEVLOG.md entries — they form the audittrail that LESSON.md is distilled from.
DEVLOG.md) orindexed (LESSON.md), and cross-link.
summaries — see When NOT to Use.
.trae/skills/devlog/
├── SKILL.md # this file
├── scripts/
│ ├── setup.sh # POSIX one-shot init
│ ├── setup.ps1 # PowerShell one-shot init
│ ├── verify-ignored.sh # assert local-only files stay untracked
│ └── verify-ignored.ps1 # PowerShell counterpart
└── references/
├── git-exclude-explained.md # why .git/info/exclude
└── categories.md # canonical LESSON.md categoriesGenerated files in the user's project (created by scripts/setup.*):
DEVLOG.md (local-only)LESSON.md (local-only)After setup, run ./scripts/verify-ignored.sh (or .ps1) to confirm both files satisfy the local-only invariant (ignored, untracked, never committed). Re-run it any time you suspect the invariant has been broken.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.