In this rapidly growing AI age we are using agent to do part of our work (but not all of it yet). The best and stable method for now is an agent integrated into the IDE where we ask for small or medium size tasks.
When I started using it, I found myself constantly asking for changes after the agent had done its work. Many were syntax issues, others were design problems, and some are not following the project standards.
Then, I've decided to put some effort into this, and create a skill. Well, actually I've asked my agent to convert the GO coding guidelines into a skill, and after some minor optimizations, it worked. Now I find myself asking the agent to do the work, and the code generated looks as if I've created it myself.
I am no longer required.
Create an Agent Skill
To apply a skill to your agent, create .agents/skills/go-guidelines/SKILL.md
name: go-guidelines
description: Apply repository Go standards to implementation, modification, refactoring, and review, including production code, tests, APIs, concurrency, logging, errors, and configuration.
---
# Apply CTO Go guidelines
1. Inspect neighboring code and packages for established patterns.
2. Read only applicable references:
- [core-style.md](references/core-style.md): always, for changes or reviews.
- [functions-and-types.md](references/functions-and-types.md): functions, signatures, structs, collections, or packages.
- [design.md](references/design.md): new components, refactors, dependencies, configuration, or serialization.
- [errors-and-logging.md](references/errors-and-logging.md): fallible or logging code.
- [runtime-and-security.md](references/runtime-and-security.md): locks, persistent memory, or backend responses containing secrets.
- [test.md](references/test.md): unit testing.
3. Apply relevant rules while preserving correctness and public contracts.
4. Treat the references as repository policy. If a rule conflicts with correctness, security, generated-code requirements, or explicit instructions, stop and report it rather than weaken either requirement.
5. In the final response, mention material exceptions and verification performed; do not enumerate rules that were followed normally.
And the create the references files under .agents/skills/go-guidelines/references/
code-style.md
## Naming
- Use complete, descriptive words, not abbreviations. Camel-case initialisms: `clientIpAddress`, not `clientIPAddress`.
- Give exported methods and exported struct fields names of at least two words (an IDE workaround).
- Use a one-letter receiver name consistently within a type's methods.
- Export only what another package must access.
## Existing conventions
- Inspect and follow nearby naming, flag, Kafka-topic, package, and construction patterns unless they violate a guideline.
- Do not introduce a competing convention in the same area.
## Comments and cleanup
- Prefer self-explanatory code. Comment only unusual behavior, non-obvious constraints, or required documentation; never narrate obvious code.
- Do not leave TODOs.
- Remove unused variables, functions, constants, comments, commented-out code, and obsolete branches.
- Remove code duplicating Go guarantees.
- Avoid duplicated logic. Extract a shared implementation when it improves clarity and maintains sensible coupling.
## Readability
- Keep nesting to at most three indentation levels. Prefer guard clauses or small cohesive functions.
- Limit function bodies to 15 executable lines. Split by responsibility without increasing coupling or creating trivial wrappers.
- Do not retain a function that only forwards to one simple statement unless it prevents meaningful duplication or provides a real abstraction boundary.
design.md
# Design and dependencies
## Cohesion and coupling
- Minimize parameter and field coupling; keep only shared dependencies and state.
- When functions repeatedly consume the same inputs, create a cohesive object that owns them instead of threading them through every call.
- Prefer object-oriented decomposition for clear ownership, encapsulation, and behavior. Every object must have a cohesive responsibility.
- Keep private implementation details unexported.
## Repository capabilities
- Before implementing common utilities, search and prefer `kit*` packages such as `kiterr`, `kitmap`, `kittime`, and `kitstring`.
- Add reusable, missing general-purpose operations to the appropriate `kit*` package instead of duplicating them locally.
## Configuration and constants
- Do not hard-code operational configuration.
- Put per-PO configuration on the PO and non-PO environment configuration through `core/config.go`.
- Create constants only for values used more than once, not merely to rename one-use literals.
## Serialization
- Add JSON tags only for external communication or Redis persistence, never internal-only structs.
errors-and-logging.md
# Errors and logging
## Error propagation
- Follow `kiterr`'s raise/recover model; do not add errors to ordinary returns.
- Recover or handle errors only at a genuine top-level boundary, such as a new goroutine entry point.
- Never hide an unexpected error. Raise it by default.
- Suppress only explicitly expected errors that retry or recovery cannot resolve; log them at WARN or higher with context.
- Do not conceal caller bugs or invalid state with nil checks, fallbacks, or skipped paths. Surface the defect.
## Diagnostic context
- Include relevant runtime values in raised errors; stack traces identify location, not failing input.
- Never include passwords, secrets, tokens, or other sensitive values in error details or logs.
## Logging
- Use the repository logger, never direct printing.
- Use `pologger` for messages related to a PO.
- Choose verbosity by expected frequency:
- V1: approximately once per minute.
- V2: approximately once per second to once per minute.
- V5: more frequently than once per second.
functions-and-types.md
# Functions and types
## Functions and control flow
- Put every parameter, even a single one, on its own line per repository formatting and nearby syntax.
- Use booleans directly: `if enabled` or `if !enabled`; never compare with `true` or `false`.
- Handle every `switch` default; raise a contextual error if it is impossible or unsupported.
- Minimize function parameters. Do not pass a value separately when it is already available through another parameter.
- Keep shared method dependencies and state in receiver fields instead of repeatedly passing them.
## Structs and packages
- Define named struct types. Do not use anonymous inline structs.
- Keep one principal class-like component per package. Follow existing layout for related helpers and types; do not harm cohesion by mechanically creating packages.
- Pass and return struct pointers, including `time.Time`, unless a required interface or established immutable-value contract dictates otherwise.
- Store struct elements in slices as pointers: `[]*Item`, not `[]Item`. This concerns elements, not pointers to slices.
- Represent empty slices as `nil` unless an external serialization contract requires `[]`.
- Replace deeply nested or otherwise complex composite types with named structs that express each layer.
runtime-and-security.md
# Runtime safety and security
## Persistent memory
- Bound every persistent in-memory collection or cache.
- Use eviction, expiration, or another limit to prevent sustained traffic exhausting pod memory.
## Backend secrets
- Never return passwords from backend APIs to the frontend.
- Exclude credentials and equivalent secrets from response models, serialization, logs, and error details.
## Locking
- Guarantee lock cleanup on every exit, including raised errors.
- Prefer a small function that acquires the lock and immediately defers its unlock before protected work.
- Minimize critical sections; avoid unknown or blocking calls while locked when possible.
test.md
# Verification
- do not create unit test in the same folder as the tested source, tests live in `images/tests/src/project/tests`.
- Follow existing test conventions.
- Prefer end-to-end simulation over testing only the updated file.
Final Note
The nice thing about this skill is that is is split to multiple sections, so first the skill is loaded only when required, and second only the relevant sub skill items are loaded, so we save tokens and optimize the agent functionality.
No comments:
Post a Comment