api
Self-hostable personal AI assistant
Install / Use
npx skills add theimaginaryfoundation/what-iffInstalls into whichever agent you are using.
Cursor Rules
Cursor IDE rules (v2)
Quality Score
Category
Development & EngineeringSupported Platforms
Our assessment of api
api scores 73/100 on our quality scale, 3757th of 4,632 Development & Engineering skills we index.
Its Cursor Rules is 20 KB long, well organised into 31 sections with 20 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
- The repository was last updated 9 days ago, so api is actively maintained.
- Our last check on 2026-10-18 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 80/100, with 2 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.
api compared with similar skills
All 4 of these similar skills score higher than api; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| api (this skill)by theimaginaryfoundation | 73 | 0 | 9d ago | Cursor Rules |
| taste-skillby Leonxlnx | 100 | 108.6k | 2d ago | CLAUDE.md |
| Agent-Reachby Panniantong | 100 | 108.0k | 1d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 78.7k | today | CLAUDE.md |
| ai-job-searchby ai-job-search-dev | 100 | 69.0k | today | CLAUDE.md |
Frequently asked questions
- How do I install api?
- Run
npx skills add theimaginaryfoundation/what-iff. The install tabs above show the steps for each supported agent. - Which AI agents does api work with?
- It is written for Cursor, as a Cursor Rules file. Other agents that read the same format can often use it too.
- Is api 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 80/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 api still maintained?
- The repository was last updated 9 days ago, so api is actively maintained.
Skill content
View source on GitHubdescription: globs: internal/auth/.go,internal/handlers/**/.go,internal/server/*.go alwaysApply: false
API Server Design and Structure
Overview
The API server is a RESTful service built with Go, using the Gorilla Mux router for routing and Ent for database operations. The server follows a modular design with clear separation of concerns and dependency injection patterns.
Server Initialization
The API server is initialized in cmd/api-server/main.go. It follows these steps:
- Load environment variables
- Initialize logger
- Connect to database
- Create and configure server
- Start server and handle graceful shutdown
func main() {
// Load environment variables
if err := godotenv.Load(envFile); err != nil {
log.Printf("Warning: Error loading .env file: %v", err)
}
// Initialize logger
logger, err := zap.NewProduction()
if err != nil {
log.Fatalf("Failed to initialize logger: %v", err)
}
defer logger.Sync()
// Initialize database connection
client, err := database.NewClient(logger)
if err != nil {
logger.Fatal("Failed to connect to database", zap.Error(err))
}
defer client.Close()
// Create server config
config := server.NewConfig()
// Create and configure server
srv := server.NewServer(config, logger, client)
// Run server in a goroutine
go func() {
if err := srv.Start(); err != nil {
logger.Fatal("Server failed", zap.Error(err))
}
}()
// Handle graceful shutdown
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
sig := <-c
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
logger.Fatal("Server forced to shutdown", zap.Error(err))
}
}
Server Configuration
Server configuration is managed through the Config struct in internal/server/config.go. It loads settings from environment variables with sensible defaults.
type Config struct {
Host string
Port string
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
RunMigrations bool
}
func NewConfig() *Config {
port := os.Getenv("SERVER_PORT")
if port == "" {
port = "8080"
}
host := os.Getenv("SERVER_HOST")
if host == "" {
host = "localhost"
}
return &Config{
Host: host,
Port: port,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second,
RunMigrations: false,
}
}
Server Structure
The server is structured around a central Server struct in internal/server/server.go which encapsulates:
- Configuration
- Logger
- Router
- HTTP server
- Database client
type Server struct {
config *Config
logger *zap.Logger
router *mux.Router
server *http.Server
db *ent.Client
}
func NewServer(config *Config, logger *zap.Logger, db *ent.Client) *Server {
s := &Server{
config: config,
logger: logger,
router: mux.NewRouter(),
db: db,
}
s.setupMiddleware()
s.setupRoutes()
s.server = &http.Server{
Addr: fmt.Sprintf("%s:%s", config.Host, config.Port),
Handler: s.router,
WriteTimeout: config.WriteTimeout,
ReadTimeout: config.ReadTimeout,
IdleTimeout: config.IdleTimeout,
}
return s
}
Provider Pattern
We use the provider pattern to decouple handlers from data access implementations. Our approach has evolved to use composite provider interfaces for handlers that need access to multiple entity types.
Entity-Specific Provider Interfaces
Each entity has its own provider interface in the internal/providers/ directory:
// ContentBriefProvider defines the interface for content brief data operations
type ContentBriefProvider interface {
CreateContentBrief(ctx context.Context, userID uuid.UUID, contentBrief models.ContentBrief) (*models.ContentBrief, error)
ListContentBriefs(ctx context.Context, userID uuid.UUID, pageNum, pageSize int, filters models.ContentBriefFilters) (*models.PaginatedResponse, error)
GetContentBrief(ctx context.Context, userID, id uuid.UUID) (*models.ContentBrief, error)
UpdateContentBrief(ctx context.Context, userID uuid.UUID, contentBrief models.ContentBrief) (*models.ContentBrief, error)
DeleteContentBrief(ctx context.Context, userID, id uuid.UUID) error
}
Composite Provider Interfaces
For handlers that need access to multiple entity types, we define composite interfaces that extend multiple entity provider interfaces:
// ProjectBriefQuestionIdeaJobProvider combines multiple provider interfaces
type ProjectBriefQuestionIdeaJobProvider interface {
providers.ProjectProvider
providers.ContentIdeaProvider
providers.ContentBriefProvider
providers.InterviewQuestionProvider
providers.JobProvider
}
This approach simplifies handler constructors and avoids large parameter lists.
Generator Interfaces
For AI-powered content generation, we define handler-specific generator interfaces that include only the methods needed by each handler:
// ContentBriefQuestionGenerator defines the interface for generating content briefs and questions
type ContentBriefQuestionGenerator interface {
GenerateContentBrief(ctx context.Context, contentIdea *models.ContentIdea, project *models.Project) (*models.CreateContentBrief, error)
GenerateInterviewQuestions(ctx context.Context, brief *models.ContentBrief) ([]*models.InterviewQuestion, string, error)
}
This approach keeps the interfaces focused and ensures that handlers only depend on the generation capabilities they actually need.
Datastore Implementation
The datastore implements all provider interfaces:
// Datastore implements various provider interfaces
type Datastore struct {
dbClient *ent.Client
logger *zap.Logger
}
func NewDatastore(dbClient *ent.Client, logger *zap.Logger) *Datastore {
return &Datastore{
dbClient: dbClient,
logger: logger,
}
}
Handler Organization
Handlers are organized by domain/resource in the internal/handlers/ directory. Each handler package follows a consistent pattern:
- Define provider and generator interfaces in
provider.go - A handler struct that depends on these interfaces in
handler.go - A constructor function that injects the dependencies
- A method to register routes with a router
- Handler methods for various operations in separate files (e.g.,
create.go,list.go, etc.)
Example handler structure:
// Handler struct holds dependencies via interfaces
type Handler struct {
dsProvider ProjectBriefQuestionDraftJobProvider
generator ContentDraftGenerator
logger *zap.Logger
}
// Constructor function with dependency injection
func NewHandler(dsProvider ProjectBriefQuestionDraftJobProvider, generator ContentDraftGenerator, logger *zap.Logger) *Handler {
return &Handler{
dsProvider: dsProvider,
generator: generator,
logger: logger,
}
}
// Route registration method
func (h *Handler) RegisterRoutes(router *mux.Router) {
resourceRouter := router.PathPrefix("/content-draft").Subrouter()
resourceRouter.HandleFunc("", h.ListContentDrafts).Methods("GET")
resourceRouter.HandleFunc("", h.CreateContentDraft).Methods("POST")
resourceRouter.HandleFunc("/generate", h.GenerateContentDraft).Methods("POST")
resourceRouter.HandleFunc("/{id}", h.GetContentDraft).Methods("GET")
resourceRouter.HandleFunc("/{id}", h.UpdateContentDraft).Methods("PUT")
resourceRouter.HandleFunc("/{id}", h.DeleteContentDraft).Methods("DELETE")
}
Path Parameter Handling
Gorilla Mux path variables should be accessed using mux.Vars(r):
// Get resource ID from URL
vars := mux.Vars(r)
idStr, ok := vars["id"]
if !ok || idStr == "" {
h.respondWithError(w, http.StatusBadRequest, "Resource ID is required", nil)
return
}
// Parse the ID
resourceID, err := uuid.Parse(idStr)
if err != nil {
h.respondWithError(w, http.StatusBadRequest, "Invalid resource ID", err)
return
}
Route Registration
Routes are registered in the setupRoutes method of the Server struct. The process follows these steps:
- Initialize data providers
- Initialize AI providers/generators
- Initialize handlers with providers and generators
- Create API router
- Set up public routes
- Set up protected routes with auth middleware
func (s *Server) setupRoutes() {
// Create data providers
dataStore := datastore.NewDatastore(s.db, s.logger)
// Create AI providers
aiProvider := ai.NewOpenAIProvider(s.logger)
// Create handlers
userHandler := user.NewUserHandler(s.db, s.logger)
contentBriefHandler := contentbrief.NewHandler(dataStore, aiProvider, s.logger)
contentDraftHandler := contentdraft.NewHandler(dataStore, aiProvider, s.logger)
// Setup API routes
apiRouter := s.router.PathPrefix("/api").Subrouter()
// Health check
apiRouter.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("API is running"))
}).Methods("GET")
// Public routes
apiRouter.HandleFunc("/users/register", userHandler.Register).Methods("POST")
apiRouter.HandleFunc("/users/login", userHandler.Login).Methods("POST")
// Protected routes
authRouter := apiRouter.NewRoute().Subrouter()
authRouter.Use(middleware.AuthMiddleware(s.db, s.logger))
// Register protected routes
userHandler.RegisterRoutes(authRouter)
contentBriefHandler.RegisterRoutes(authRouter)
contentDraftHandler.RegisterRoutes(authRouter)
}
Authentication
Authentication is handled using JWT tokens. The internal/auth package provides functions for:
- Generating access and refresh tokens
- Validating tokens
- Refreshing tokens
- Password hashing and verification
// Generate token pair
tokenPair, tokenID, err := auth.GenerateTokenPair(user.ID, user.Role)
// Validate access token
claims, err := auth.ValidateAccessToken(tokenString)
// Refresh access token
newAccessToken, err := auth.RefreshAccessToken(refreshToken)
// Hash password
hashedPassword, err := auth.HashPassword(password)
// Check password
isValid := auth.CheckPassword(password, hashedPassword)
Authentication Middleware
The authentication middleware extracts and validates the JWT token from the Authorization header and adds the user ID to the request context.
func AuthMiddleware(client *ent.Client, logger *zap.Logger) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Extract the token
tokenString := strings.Replace(authHeader, "Bearer ", "", 1)
// Validate the token
claims, err := auth.ValidateAccessToken(tokenString)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Add user ID to context
ctx := context.WithValue(r.Context(), UserIDKey, claims.UserID)
// Call the next handler with the updated context
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
Handler Utilities
The internal/handlers/handlerutils package provides common utilities for handlers:
HTTP Response Utilities
// Respond w
Truncated for display — read the full file on GitHub.
Related Skills
taste-skill
108.6kAgent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages
Agent-Reach
108.0kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
78.7kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ai-job-search
69.0kThe 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.
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.
