A Custom OpenClaw Skill for TodayIngoLearned

In 2020, I developed TodayIngoLearned (blog post), a personal knowledge and learning management system based on the idea of storing the things I learn during the day.
Since then, the project (see GitHub) has slowly evolved – but strictly as a private project which only ever gets updated when I need or want a new feature.
As one does, I have been playing around with OpenClaw a lot lately, and as part of that, integrating TodayIngoLearned into my OpenClaw agent was quite obvious. Hence, I want to take this opportunity to share how to build a simple custom Skill for OpenClaw, focused on an equally simple REST API.
The Prerequisite: The REST API
Of course, a REST API is not necessarily a prerequisite for an agent skill, but it makes life a lot simpler. In the case of TodayIngoLearned, a very simple API already exists.
The three relevant features are searching, retrieving, and creating so-called “TILs” – entries in the knowledge database.
Using curl this looks something like this:
Searching
curl -H "X-API-Key: til_XXX" "https://todayingolearned.til/api/v1/til/search?type=title&q=openclaw"
Retrieving
curl -H "X-API-Key: til_XXX" https://todayingolearned.til/api/v1/til/1
Creating
curl -X POST https://todayingolearned.til/api/v1/til ^
-H "X-API-Key: til_XXX" ^
-H "Content-Type: application/json" ^
-d "{\"title\": \"OpenClaw\", \"description\": \"It's an agent!\", \"date\": \"2026-03-22\"}"
As you might have realized, this is not a full CRUD API. This is on purpose as I don’t (yet) want my agent(s) to be able to make changes or delete content.
Developing Custom OpenClaw Skill
An OpenClaw Skill, at the end of the day, is a directory with a SKILL.md markdown file and potentially some additional tools and helpers. This makes sense as OpenClaw follows the Agent Skills standard.
Hence, on a file level, the TodayIngoLearned Skill looks like this:
* todayingolearned
* SKILL.md
* scripts
* til_create.sh
* til_get.sh
* til_search.sh
After some testing, I decided to create scripts for the key actions instead of just relying on providing curl-examples in the SKILL.md.
SKILL.md
---
name: todayingolearned
description: Read, create, and search learnings in the TodayIngoLearned personal knowledge platform via its HTTP API.
metadata:
openclaw:
primaryEnv: TIL_API_KEY
---
# TodayIngoLearned
Use this skill to read, create, and search "learnings" in the TodayIngoLearned API.
## When to use
- The user wants to save a new learning / TIL
- The user says they learned something and wants it stored
- The user wants to fetch a learning by ID
- The user wants to search existing learnings
- The user mentions TodayIngoLearned or `todayingolearned.til`
## Configuration
This skill expects:
- `TIL_API_KEY`
- optional `TIL_BASE_URL` which defaults to `https://todayingolearned.til`
## API
Create learning:
- `POST /api/v1/til`
- JSON body:
- `title`
- `description`
- `date` in `YYYY-MM-DD`
Read learning by ID:
- `GET /api/v1/til/{id}`
Search learnings:
- `GET /api/v1/til/search?type=TYPE&q=QUERY`
- supported `type` values:
- `title`
- `tag`
## Workflows
### Create a learning
When the user wants to store a learning:
1. Infer or ask for:
- title
- description
- date
2. Default `date` to today if the user does not specify one.
3. Call:
bash scripts/til_create.sh "TITLE" "DESCRIPTION" "YYYY-MM-DD"
4. Summarize the result briefly.
### Read a learning
When the user wants to retrieve a learning by ID:
1. Extract the numeric ID.
2. Call:
bash scripts/til_get.sh "ID"
3. Return the learning in readable form.
### Search learnings
When the user wants to search existing learnings:
1. Determine the search type:
- use `title` for normal keyword search
- use `tag` for hashtag search such as `#misc`
2. Call:
bash scripts/til_search.sh "TYPE" "QUERY"
3. Summarize the results clearly.
4. Preserve hashtags exactly when doing tag searches.
## Examples
### Create
bash scripts/til_create.sh "My TIL" "Learned something about curl #misc" "2026-03-21"
### Read
bash scripts/til_get.sh "1"
### Search by title
bash scripts/til_search.sh "title" "javascript"
### Search by tag
bash scripts/til_search.sh "tag" "#misc"
## Notes
- Prefer concise titles when creating entries.
- Keep hashtags like `#misc` in the description if the user includes them.
- For tag searches, include the leading `#`.
- If the API returns an error, explain it clearly.
- If the user does not specify a date when creating a learning, use today's date.
As you can see, a “skill” is essentially a narrative description, including examples, on how to do things. Having the scripts available makes this a little bit easier, as there is no confusion about the correct curl calls.
A key point here is the primaryEnv: TIL_API_KEY in the header. This allows us to set the API key within OpenClaw so that we don’t have to worry about either hardcoding it or managing .env files ourselves.
Scripts
Below are the three helper scripts. While not strictly necessary and quite boring, they reduce the surface area for potential mistakes.
til_create.sh
#!/usr/bin/env bash
set -euo pipefail
TITLE="${1:-}"
DESCRIPTION="${2:-}"
DATE_VALUE="${3:-}"
if [[ -z "$TITLE" || -z "$DESCRIPTION" || -z "$DATE_VALUE" ]]; then
echo "Usage: $0 <title> <description> <date>" >&2
exit 1
fi
API_BASE="${TIL_BASE_URL:-https://todayingolearned.til}"
API_KEY="${TIL_API_KEY:?TIL_API_KEY is required}"
curl --silent --show-error --fail \
-X POST "${API_BASE%/}/api/v1/til" \
-H "X-API-Key: ${API_KEY}" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg title "$TITLE" \
--arg description "$DESCRIPTION" \
--arg date "$DATE_VALUE" \
'{title: $title, description: $description, date: $date}')"
til_get.sh
#!/usr/bin/env bash
set -euo pipefail
ID="${1:-}"
if [[ -z "$ID" ]]; then
echo "Usage: $0 <id>" >&2
exit 1
fi
API_BASE="${TIL_BASE_URL:-https://todayingolearned.til}"
API_KEY="${TIL_API_KEY:?TIL_API_KEY is required}"
curl --silent --show-error --fail \
-H "X-API-Key: ${API_KEY}" \
"${API_BASE%/}/api/v1/til/${ID}"
til_search.sh
#!/usr/bin/env bash
set -euo pipefail
TYPE="${1:-}"
QUERY="${2:-}"
if [[ -z "$TYPE" || -z "$QUERY" ]]; then
echo "Usage: $0 <type> <query>" >&2
exit 1
fi
case "$TYPE" in
title|tag)
;;
*)
echo "Error: type must be 'title' or 'tag'" >&2
exit 1
;;
esac
API_BASE="${TIL_BASE_URL:-https://todayingolearned.til}"
API_KEY="${TIL_API_KEY:?TIL_API_KEY is required}"
curl --silent --show-error --fail \
-G "${API_BASE%/}/api/v1/til/search" \
-H "X-API-Key: ${API_KEY}" \
--data-urlencode "type=${TYPE}" \
--data-urlencode "q=${QUERY}"
A Note on Model Quality
I am currently also testing various (open) models with OpenClaw. When using the otherwise really great Mistral Small 3.2 24B Instruct, I was unable to get the skill to work consistently. Switching to the more powerful OpenAI GPT OSS 120B – simply because I had it available on my inference service – solved this issue immediately.
While this is absolutely to be expected, it highlights that we have entered a stage of AI/LLM/agent development in which the question of how much “intelligence” is needed, given cost, environmental impact, etc., for a given task is becoming increasingly important and practical.
Conclusion
While it sounds highly technical, agent skills are “just” bundled prompts and tools – and that is a good thing. The technical barrier to building custom skills is relatively low, and creating custom skills, in many cases, is primarily about clearly defining problems, use cases, and examples rather than software development.
The cool thing: Even though it is relatively easy to create custom skills, this approach, given powerful enough models, actually works and makes agents like OpenClaw useful. With only a few lines of text and code that can be easily generated, I now have a convenient conversational interface for my knowledge/learning management system, built on pre-existing APIs.
Thank you for visiting!
I hope, you are enjoying the article! I'd love to get in touch! 😀
Follow me on LinkedIn