skrift-forms
Skrift form system — Pydantic-backed forms with CSRF protection, template rendering, and hook integration.
Install / Use
npx skills add Smarter-Dev/smarter-dev --skill skrift-formsInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Development & EngineeringSupported Platforms
Tags
Our assessment of skrift-forms
skrift-forms scores 66/100 on our quality scale, 3914th of 4,617 Development & Engineering skills we index.
Its SKILL.md is 6.8 KB long, well organised into 18 sections with 10 code examples: a thorough specification that gives an agent plenty to work with.
It has no GitHub stars yet, so there is no community track record; judge it on its content.
Maintenance, license and trust
- We could not determine when the repository was last updated.
- Our last check on 2026-10-19 found the source still online.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 68/100, with 3 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.
AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
skrift-forms compared with similar skills
All 4 of these similar skills score higher than skrift-forms; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| skrift-forms (this skill)by Smarter-Dev | 66 | 0 | — | SKILL.md |
| taste-skillby Leonxlnx | 100 | 110.6k | today | CLAUDE.md |
| ai-job-searchby ai-job-search-dev | 100 | 69.8k | today | CLAUDE.md |
| claude-howtoby luongnv89 | 100 | 46.6k | 2d ago | CLAUDE.md |
| algorithmic-artby anthropics | 100 | 177.9k | 44d ago | SKILL.md |
Frequently asked questions
- How do I install skrift-forms?
- Run
npx skills add Smarter-Dev/smarter-dev --skill skrift-forms. The install tabs above show the steps for each supported agent. - Which AI agents does skrift-forms work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is skrift-forms safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It declares no license and scores 68/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is skrift-forms still maintained?
- We could not determine when the repository was last updated.
Skill content
View source on GitHubname: skrift-forms description: "Skrift form system — Pydantic-backed forms with CSRF protection, template rendering, and hook integration."
Skrift Form System
Skrift forms combine Pydantic validation with CSRF protection, template rendering, and hook integration.
Architecture
FormModel/BaseModel → Form(model, request) → validate() → hooks → data
│ │ │ │
│ │ │ ├─ form_{name}_validated
│ │ │ └─ form_validated
│ │ │
│ │ ├─ CSRF verify (hmac.compare_digest)
│ │ ├─ Token rotation (single-use)
│ │ ├─ Checkbox injection (bool fields)
│ │ └─ Pydantic validation
│ │
│ ├─ render() → Template("form", name).try_render()
│ ├─ csrf_field() → hidden input
│ ├─ fields → dict[str, BoundField]
│ └─ errors → dict[str, str]
│
└─ Registered in _form_registry (by form_name)
Defining Forms
FormModel (auto-registers)
from skrift.forms import FormModel
from pydantic import Field, EmailStr
class ContactForm(FormModel, form_name="contact"):
name: str
email: EmailStr
message: str = Field(json_schema_extra={"widget": "textarea"})
@form() Decorator (registers a plain BaseModel)
from pydantic import BaseModel
from skrift.forms import form
@form("newsletter", action="/subscribe", method="post")
class NewsletterForm(BaseModel):
email: str
Field Customization via json_schema_extra
| Key | Values | Purpose |
|-----|--------|---------|
| label | str | Custom label text |
| widget | "textarea", "select", "checkbox" | Widget type |
| input_type | "email", "password", etc. | HTML input type |
| help_text | str | Help text below field |
| choices | list[tuple[str, str]] | Options for select widget |
| attrs | dict[str, str] | Extra HTML attributes |
Full example:
class ContactForm(FormModel, form_name="contact"):
name: str = Field(json_schema_extra={
"label": "Your Name",
"attrs": {"placeholder": "Jane Doe"},
})
email: EmailStr = Field(json_schema_extra={
"label": "Email Address",
"input_type": "email",
"help_text": "We'll never share your email.",
})
subject: str = Field(json_schema_extra={
"widget": "select",
"choices": [
("general", "General Inquiry"),
("support", "Technical Support"),
],
})
message: str = Field(json_schema_extra={
"widget": "textarea",
"attrs": {"rows": "6"},
})
subscribe: bool = Field(default=False, json_schema_extra={
"label": "Subscribe to newsletter",
})
Controller GET/POST Pattern
from litestar import Controller, get, post, Request
from litestar.response import Template as TemplateResponse, Redirect
from skrift.forms import Form
class ContactController(Controller):
path = "/contact"
@get("/")
async def show(self, request: Request) -> TemplateResponse:
form = Form(ContactForm, request)
return TemplateResponse("contact.html", context={"form": form})
@post("/")
async def submit(self, request: Request) -> TemplateResponse | Redirect:
form = Form(ContactForm, request)
if await form.validate():
# form.data is a validated ContactForm instance
await process_contact(form.data)
return Redirect("/contact?thanks=1")
return TemplateResponse("contact.html", context={"form": form})
Template Rendering
Automatic
{{ form.render() }}
{{ form.render(submit_label="Send") }}
Manual
<form method="{{ form.method }}">
{{ form.csrf_field() }}
{% for field in form %}
{{ field.label_tag() }}
{{ field.widget() }}
{% endfor %}
<button type="submit">Send</button>
</form>
Custom Form Template
Template hierarchy: form-{name}.html → form.html → programmatic fallback.
{# templates/form-contact.html #}
<form method="{{ form.method }}" class="contact-form">
{{ form.csrf_field() }}
{% if form.form_error %}
<div class="alert">{{ form.form_error }}</div>
{% endif %}
<div class="row">
<div class="col">
{{ form['name'].label_tag() }}
{{ form['name'].widget(class_="form-input") }}
</div>
<div class="col">
{{ form['email'].label_tag() }}
{{ form['email'].widget(class_="form-input") }}
</div>
</div>
{{ form['message'].label_tag() }}
{{ form['message'].widget(class_="form-input", rows="8") }}
<button type="submit">{{ submit_label }}</button>
</form>
CSRF Flow
Form.__init__()— Createssecrets.token_urlsafe(32)in session if absent (key:_csrf_token)csrf_field()— Renders<input type="hidden" name="_csrf" value="{token}">validate()— Checks submitted_csrfagainst session token viahmac.compare_digest()- Token rotation — New token generated after successful check (single-use)
Registration Mechanism
Forms are registered in a global _form_registry dict (in model.py):
FormModel.__init_subclass__()auto-registers on class creation@form()decorator registers explicitlyget_form_model(name)retrieves by name, raisesLookupErrorif missing
Hook Integration
Two filter hooks fire after successful validation:
# Form-specific: e.g. "form_contact_validated"
self.data = await hooks.apply_filters(f"form_{self.name}_validated", self.data)
# Global: "form_validated"
self.data = await hooks.apply_filters("form_validated", self.data, self.name)
Example hook:
from skrift.hooks import filter
@filter("form_contact_validated")
async def sanitize_contact(data):
data.message = data.message.strip()
return data
@filter("form_validated")
async def log_all_forms(data, name):
print(f"Form '{name}' submitted")
return data
Jinja2 Global
The Form class is registered as a Jinja2 global, making it accessible in templates without passing it through context.
Key Files
| File | Purpose |
|------|---------|
| skrift/forms/core.py | Form — CSRF, validation, rendering |
| skrift/forms/model.py | FormModel base class, _form_registry, get_form_model() |
| skrift/forms/fields.py | BoundField — field bound to form instance |
| skrift/forms/decorators.py | @form() decorator |
| skrift/templates/form.html | Default form template |
Related Skills
taste-skill
110.6kAgent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages
ai-job-search
69.8kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
claude-howto
46.6kA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
