agentleFS
I-OnlabsI-Onlabs/claude-code-skills/firebase-buddy/SKILL.md

firebase-buddy

Skill4 starsChanged 16 days agoMITView on GitHub

Firebase patterns and troubleshooting for vibecoders. Use when user mentions Firebase, Firestore, Firebase Auth, Firebase hosting, security rules, or is working on projects using Firebase backend. Also use for errors like "permission denied", "missing index", or authentication issues in Firebase projects.

  • Reads credentials
  • Installs packages

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Restart dev server: after changing .env.local

    line 318

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Firebase Buddy

Common Firebase patterns without the complexity.

Quick Setup Checklist

  1. Install Firebase:
    npm install firebase
  2. Create config file (lib/firebase.js or firebase.ts):
    import { initializeApp } from 'firebase/app';
    import { getFirestore } from 'firebase/firestore';
    import { getAuth } from 'firebase/auth';
    import { getStorage } from 'firebase/storage';
    
    const firebaseConfig = {
      apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
      authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
      projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
      storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
      messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
      appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
    };
    
    const app = initializeApp(firebaseConfig);
    export const db = getFirestore(app);
    export const auth = getAuth(app);
    export const storage = getStorage(app);
  3. Create .env.local:
    NEXT_PUBLIC_FIREBASE_API_KEY=your-key
    NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
    NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project
    NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
    NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456
    NEXT_PUBLIC_FIREBASE_APP_ID=1:123:web:abc

Firestore Patterns

Read Data

import { doc, getDoc, collection, getDocs, query, where, orderBy, limit } from 'firebase/firestore';
import { db } from './firebase';

// Get one document
const docSnap = await getDoc(doc(db, 'users', 'userId'));
if (docSnap.exists()) {
  console.log(docSnap.data());
}

// Get all documents in collection
const querySnapshot = await getDocs(collection(db, 'users'));
querySnapshot.forEach((doc) => {
  console.log(doc.id, doc.data());
});

// Query with filters
const q = query(
  collection(db, 'posts'),
  where('author', '==', 'userId'),
  orderBy('createdAt', 'desc'),
  limit(10)
);
const results = await getDocs(q);

Write Data

import { doc, setDoc, addDoc, updateDoc, deleteDoc, collection, serverTimestamp } from 'firebase/firestore';
import { db } from './firebase';

// Set with specific ID
await setDoc(doc(db, 'users', 'userId'), {
  name: 'John',
  email: 'john@example.com',
  createdAt: serverTimestamp()
});

// Add with auto-generated ID
const docRef = await addDoc(collection(db, 'users'), {
  name: 'Jane',
  email: 'jane@example.com'
});
console.log('New doc ID:', docRef.id);

// Update specific fields
await updateDoc(doc(db, 'users', 'userId'), {
  name: 'John Updated'
});

// Delete
await deleteDoc(doc(db, 'users', 'userId'));

Real-time Listener

import { doc, collection, onSnapshot, query, where } from 'firebase/firestore';
import { db } from './firebase';

// Listen to one document
const unsubscribe = onSnapshot(doc(db, 'users', 'userId'), (doc) => {
  console.log('Current data:', doc.data());
});

// Listen to collection with query
const q = query(collection(db, 'messages'), where('roomId', '==', 'room1'));
const unsubscribe = onSnapshot(q, (snapshot) => {
  snapshot.forEach((doc) => {
    console.log(doc.data());
  });
});

// Call unsubscribe() to stop listening (important for cleanup!)

React Hook Pattern

import { useState, useEffect } from 'react';
import { doc, onSnapshot } from 'firebase/firestore';
import { db } from './firebase';

function useDocument(collectionName, docId) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onSnapshot(doc(db, collectionName, docId), (doc) => {
      setData(doc.exists() ? { id: doc.id, ...doc.data() } : null);
      setLoading(false);
    });
    return unsubscribe; // cleanup on unmount
  }, [collectionName, docId]);

  return { data, loading };
}

Authentication

Email/Password

import { 
  signInWithEmailAndPassword, 
  createUserWithEmailAndPassword, 
  signOut,
  onAuthStateChanged 
} from 'firebase/auth';
import { auth } from './firebase';

// Sign up
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
const user = userCredential.user;

// Sign in
await signInWithEmailAndPassword(auth, email, password);

// Sign out
await signOut(auth);

// Listen to auth state
onAuthStateChanged(auth, (user) => {
  if (user) {
    console.log('Logged in:', user.uid);
  } else {
    console.log('Logged out');
  }
});

Google Sign-In

import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
import { auth } from './firebase';

const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
const user = result.user;

Auth Context (React)

import { createContext, useContext, useEffect, useState } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from './firebase';

const AuthContext = createContext({});

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
      setLoading(false);
    });
    return unsubscribe;
  }, []);

  return (
    <AuthContext.Provider value={{ user, loading }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);

Storage (File Uploads)

import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { storage } from './firebase';

// Upload file
const storageRef = ref(storage, `uploads/${file.name}`);
await uploadBytes(storageRef, file);

// Get download URL
const url = await getDownloadURL(storageRef);
console.log('File URL:', url);

Common Errors & Fixes

ErrorMeaningFix
"permission-denied"Security rules blocking accessUpdate Firestore rules (see below)
"not-found"Document doesn't existCheck path, check if data exists
"unauthenticated"User not logged inSign in first, or update rules
"missing index"Query needs an indexClick link in error to create index
"quota exceeded"Free tier limit hitWait or upgrade plan
"invalid-argument"Wrong data type or formatCheck your data matches expected types
"already-exists"Trying to create existing docUse setDoc with merge, or update

Security Rules Quick Reference

Development (allow everything — NOT for production):

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

Allow authenticated users only:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Users can only access their own data:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    match /users/{userId}/posts/{postId} {
      allow read: if true;
      allow write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Firebase CLI

# Install
npm install -g firebase-tools

# Login
firebase login

# Initialize project
firebase init

# Deploy rules
firebase deploy --only firestore:rules

# Deploy hosting
firebase deploy --only hosting

# View logs
firebase functions:log

Debugging Tips

  1. Check the Firebase Console — see actual data and errors
  2. Check auth state — console.log(auth.currentUser)
  3. Check network tab — see actual requests/responses
  4. Rules Playground — test rules in Firebase Console
  5. Restart dev server after changing .env.local
  6. Check indexes — Firestore → Indexes in console
  7. Use emulators — firebase emulators:start for local testing

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.