v1.0.0
PHPShift Home
PHPShift logo

PHPShift

World's First AI-Powered Full-Stack Framework

Irakli Gzirishvili, creator of PHPShift

Irakli Gzirishvili

Creator of PHPShift

Overview

PHPShift is the world's first AI-powered full-stack PHP framework, launched on December 19, 2024. It eliminates the traditional development grind by letting you describe what you want in plain language - and having AI generate production-ready PHP pages, REST APIs, cron jobs, translations, SEO markup and database schemas for you.

At its core, PHPShift is a CLI-driven development environment built on Python, wrapping a structured PHP project frame. You interact with it through a terminal menu; it handles localhost orchestration (XAMPP), database management (MySQL via SQLAlchemy), Git version control and AI code generation - all from one unified interface.

What PHPShift Is

PHPShift is not a library you import. It is a project generator and manager: you run it alongside your project directory and it scaffolds, modifies and maintains your PHP web application through AI conversations and structured skill prompts.

Every generation action in PHPShift is called a Skill. Skills are categorized by intent: Create, Edit, Delete, Read, Render and More. Each Skill carries a carefully engineered AI prompt that understands your project's existing codebase, database schema and PHP method surface before producing any code.

Project Structure at a Glance

A PHPShift-managed project contains these top-level elements:

Who Builds PHPShift Projects

PHPShift targets developers and technical builders who want to move fast on full-stack PHP projects without writing every line manually. It is ideal for:

Benefits

PHPShift compresses what normally takes days of scaffolding, wiring and boilerplate into a single CLI session. Here is what that means in practice.

AI-First Code Generation

Every page, API and cron job is generated by an AI that already knows your project. Before it writes a single line, the AI receives:

This context window means generated code is consistent with what already exists - not generic boilerplate pasted from the internet.

Structured Full-Stack Output

A single "Create Page" action produces all of these in one shot:

You review the result, confirm or redo it and the patch system handles rollback if you decline.

Reversible by Design

PHPShift wraps every AI generation action in a patch system. Before writing anything, it snapshots current file states. If the output is wrong, one keypress rolls back every file change and every database mutation - as if the action never happened.

Integrated Localhost Management

PHPShift automates XAMPP configuration. When you start a project, it:

  1. Creates a virtual host entry in Apache's httpd-vhosts.conf
  2. Adds the domain to the Windows hosts file
  3. Starts XAMPP's Apache and MySQL services
  4. Opens your project in the browser

Stopping the project reverses the process cleanly.

Git-Native Workflow

After every successful generation, PHPShift asks if you want to commit. It handles git add, git commit and optionally git push - keeping your history granular and meaningful without requiring you to leave the CLI.

Multi-Model AI Support

PHPShift supports multiple AI providers. You can switch models mid-project using the More > ChangeAIModel skill. Google Vertex AI (with service account key files) and API-key-based models are both supported.

Built-In Internationalization

The translation skill adds multi-language support to any page in one step: it updates HTML attributes, CSS positioning, JavaScript App.lng() calls, PHP App::lng() calls and generates the translation JSON file - all from a single natural language request.

Security Out of the Box

The generated .htaccess enforces:

Framework-level security is not an afterthought. There is even a dedicated PHPShift > RefineSecurity skill that runs a penetration-expert AI analysis of your framework codebase and reports exploitable vulnerabilities.

How It Works

PHPShift operates as a Python CLI application that sits beside your PHP project and orchestrates AI, localhost, database and version control through a terminal menu.

The Core Loop

When you run phpshift start, the following happens:

  1. Environment validation - PHPShift reads your project's .env to confirm it's configured with an AI model, API key, database credentials and local domain.
  2. Localhost startup - XAMPP is started, a virtual host is configured and your browser opens the project URL.
  3. Database initialization - The project database is connected (or created from setup.sql if new). You choose how to handle pre-existing databases: clear, keep, or rename.
  4. Cron thread - If cron jobs exist, you're asked whether to start them. PHPShift runs a background thread that fires php cron -auto once per minute.
  5. Skill menu - The interactive CLI menu appears. Options are dynamically filtered based on project state (e.g., "Edit API" only appears if APIs exist, "Create Translation" only if pages exist).

The Skill Execution Pipeline

When you select a skill and describe your task:

  1. Patch snapshot - Current state of affected files is saved for rollback.
  2. Database reservation - Pending DB changes are staged.
  3. Context collection - The AI's prompt template is populated with live project data using Collectors: schema, file list, PHP methods, JS methods, styling, etc.
  4. AI generation - The fully-assembled prompt is sent to the AI model. The response contains structured file blocks (each in a named markdown code block).
  5. File injection - PHPShift parses the AI's response, extracts each file and writes it to disk.
  6. DB execution - If a db.sql file was generated, you're shown it in VS Code and asked to confirm before it's applied to the database.
  7. Review and confirm - You're prompted: Yes (keep changes and optionally commit), Redo (roll back and try again with an adjusted description), or No (roll back entirely).

The .md Project Briefing File

Every PHPShift project has a hidden .md file at its root. This is your project briefing document - a structured markdown file describing the project name, audience, problem, solution, pages, APIs, cron jobs, usage flow and functionality notes.

The AI reads this file when generating or refining your project plan. You can edit it manually in VS Code at any time, or use the More > RefineIdea skill to have the AI generate or improve it based on a short description.

Skill Categories

| Category | Purpose | |----------|---------| | Create | Generate new pages, APIs, cron jobs, translations, SEO, README, LICENSE | | Edit | Modify existing units using AI with full codebase context | | Delete | Remove pages, APIs, cron jobs, logs, translations and related files | | Read | AI-assisted database querying, git command generation, log analysis | | Render | Re-render an existing page or generate a new access group method | | More | Change AI model, manage cron start/stop, export DB schema, install Composer plugins | | PHPShift | Self-hosted: update PHPShift, view documentation, visit PHPShift site |

File Naming Conventions

PHPShift enforces strict naming rules generated by AI:

Requirements

Before setting up a PHPShift project, make sure your environment meets the following requirements.

Operating System

PHPShift is currently designed for Windows. The localhost management module directly interacts with:

Linux and macOS support would require modifications to the localhost management module.

Required Software

| Software | Purpose | |----------|---------| | XAMPP | Local Apache + MySQL server (C:/xampp) | | Python 3.x | PHPShift CLI runtime | | PHP (via XAMPP) | Project execution | | MySQL (via XAMPP) | Project database | | VS Code | Default editor (PHPShift opens files in code) | | Git | Version control (optional but recommended) |

Python Dependencies

PHPShift uses the following Python packages (installed alongside PHPShift):

AI Model and API Key

You need one of the following:

You select and configure your AI model during phpshift new project setup and can change it later with More > ChangeAIModel.

Database

PHPShift requires a running MySQL server (port 3306 by default, via XAMPP). During project creation, you provide:

The framework auto-runs setup.sql on first start to create system tables (user_files, user_keys, api).

Installation

PHPShift is distributed as a Python package via the clight ecosystem. The installation process sets up the PHPShift CLI command, its internal .system frame and all required Python dependencies.

Install PHPShift

Install PHPShift using pip:

pip install phpshift

This makes the phpshift command available globally in your terminal.

Verify Installation

phpshift --version

You should see the current PHPShift version number.

XAMPP Setup

Ensure XAMPP is installed at C:/xampp with both Apache and MySQL modules enabled. PHPShift looks for:

C:/xampp/xampp_start.exe
C:/xampp/apache/logs/httpd.pid
C:/xampp/mysql/data/mysql.pid
C:/xampp/apache/conf/extra/httpd-vhosts.conf

If XAMPP is already running when you start a PHPShift project, PHPShift will detect it and skip the start step.

VS Code Setup (Recommended)

PHPShift automatically opens files in VS Code using the code command. Make sure VS Code's CLI is in your system PATH:

  1. Open VS Code
  2. Press Ctrl+Shift+P → type Shell Command: Install 'code' command in PATH
  3. Confirm installation

PHPShift will open your .md briefing file, .env config and SQL migration files in VS Code automatically during the workflow.

First Run Check

After installation, navigate to an empty folder where you want your first project and run:

phpshift new

PHPShift will begin the interactive project creation process. See Getting Started → First Project for a full walkthrough.

Updating PHPShift

To update PHPShift to the latest version:

phpshift update

Or via pip:

pip install --upgrade phpshift

The PHPShift > Update skill inside the development session also handles updates from within the tool.

First Project

This walkthrough takes you from an empty folder to a running PHPShift project with your first AI-generated page.

Step 1 - Create a New Project

Open a terminal in your desired project directory and run:

phpshift new

PHPShift will prompt you for project details. These values are injected into your project's .env and initial files:

| Prompt | Example | |--------|---------| | Project name | My App | | Project author | John Doe | | Local domain | myapp.local | | Production domain | myapp.com | | Database host | localhost | | Database name | myapp_db | | Database user | root | | Database password | (your MySQL root password) | | AI model | (select from list) | | AI key / key file | (your API key) |

After entering these, PHPShift:

  1. Copies the project frame files into your directory
  2. Generates a secure random APP_KEY
  3. Asks if you want to initialize Git
  4. Asks if you want to refine your project idea (AI generates a .md plan)
  5. Installs a LICENSE file
  6. Creates a VS Code workspace shortcut on your Desktop
  7. Opens code .md so you can review your project plan

Step 2 - Refine Your Idea (Optional)

When prompted "Want to refine your idea?", type a short description of your project:

A task management app where users can create, assign and track tasks in teams

The AI generates a structured .md project plan. Review it in VS Code. If you like it, confirm - the plan is saved and will guide future AI generations. If not, it's rolled back.

Step 3 - Start Development

When asked "Want to start development?", answer Yes. Or start later with:

phpshift start

PHPShift will: - Configure and start XAMPP (Apache + MySQL) - Add your local domain to the hosts file and Apache virtual hosts - Connect to the database (create it if needed) - Open your project in the browser - Launch the interactive skill menu

Step 4 - Create Your First Page

In the skill menu, select Create → Page, then describe your page:

A public landing page with a hero section, feature highlights and a call-to-action button that links to registration

PHPShift collects project context (schema, PHP methods, JS methods) and sends it to the AI. In a few seconds, it writes:

If a database table is needed, db.sql appears in VS Code for your review before being applied.

Step 5 - Review and Confirm

The CLI asks: "Want to keep changes?"

Step 6 - View Your Page

Open your browser at http://myapp.local/welcome and see the generated page live. Iterate by selecting Edit → Page to refine it.

Stopping the Project

When done for the day:

phpshift stop

Or select the exit option in the skill menu. PHPShift removes the virtual host, updates the hosts file and stops XAMPP (if no other projects are running).

Framework Structure

A PHPShift project has a well-defined directory layout. Understanding this structure helps you navigate the generated codebase and know what each part is responsible for.

Top-Level Directory Layout

my-project/
├── .assets/              # Public static assets served by Apache
│   ├── script.js         # Global jQook/jQuery app logic
│   ├── style.css         # Global base styles
│   ├── logo.png          # Project logo
│   ├── default.png       # Default image placeholder
│   ├── default.mp4       # Default video placeholder
│   ├── default.mp3       # Default audio placeholder
│   ├── robots.txt        # Search engine crawl rules
│   ├── sitemap.xml       # Auto-updated sitemap
│   └── background.webp   # Background asset
├── .system/              # PHP framework engine (internal, not public)
│   ├── app.php           # Router entry point (all requests route here via .htaccess)
│   ├── composer.json     # Composer dependency manifest
│   └── vendor/           # Composer-installed PHP packages
├── Apis/                 # PHP REST API files
│   └── v1.example.php
├── Crons/                # PHP cron job scripts
│   └── updateItems.php
├── Pages/                # Full-stack page units
│   ├── public.welcome/
│   │   ├── readme.md     # Page documentation
│   │   ├── page.html     # HTML structure
│   │   ├── style.css     # Page styles
│   │   ├── script.js     # Page JavaScript
│   │   └── code.php      # PHP business logic class
│   └── private.dashboard/
│       └── ...
├── Space/                # Project-level data files
│   ├── seo.html          # SEO meta tags (Open Graph, Twitter Card, etc.)
│   ├── lng.en.json       # English translation keys (auto-generated)
│   ├── lng.ka.json       # Georgian translation keys
│   └── *.log             # Application log files
├── .access               # PHP Access class - defines page access groups
├── .env                  # Environment configuration (never public)
├── .htaccess             # Apache routing, security headers, rate limiting
├── .gitignore            # Git ignore rules
├── .md                   # AI-readable project briefing (hidden file)
├── README.md             # Project readme (AI-generated or manual)
├── LICENSE               # Project license file
└── cron                  # PHP cron runner entry point

The .system/ Directory

This is the internal PHP framework engine. It is not editable by AI generation - it is the stable base that powers routing, authentication, database ORM, API dispatch, cron execution and the App helper class.

Key PHP method families available to generated code:

All custom PHP classes in pages and APIs extend this surface through static method calls.

The Page Unit Structure

Each page lives in a folder named {group}.{name} inside Pages/. For example, a public dashboard page lives at Pages/public.dashboard/.

The group determines access control. The .access PHP class defines static methods named after groups:

class Access {
    public static function private() {
        // Return true if current user passes the 'private' group check
    }
}

PHPShift generates group methods automatically if a new group is detected during page creation.

URL Routing

All HTTP requests are routed through .htaccess to .system/app.php. The router maps:

PHP Layer

The PHP layer is the server-side runtime for every PHPShift project. It is driven by a framework engine inside .system/ that handles routing, access control, database ORM, API dispatch and cron execution. Generated code lives on top of this engine.

Page Classes

Every page has a corresponding PHP class in its code.php file. Classes follow a strict naming convention:

The class is a plain PHP class with public methods. Each public method is directly callable from the front-end via JavaScript's App.call():

class PageDashboard
{
    public function getStats($post = [], $get = [], $files = [])
    {
        $stats = DB::query("SELECT COUNT(*) as total FROM tasks WHERE user = :uid", [
            ':uid' => App::env('CURRENT_USER_ID')
        ]);
        return App::done('Stats loaded', ['stats' => $stats]);
    }

    private function validateAccess($userId)
    {
        // Private helper - not callable from front-end
    }
}

Method arguments are always ($post = [], $get = [], $files = []) - populated automatically by the framework from the incoming HTTP request.

API Files

API files live in Apis/ and follow a similar pattern, but declare their category and allowed HTTP method at the top:

<?php category('public', 'GET');

class ApiGetItems
{
    public function init($json = [], $post = [], $get = [])
    {
        // API entry point - always named 'init'
        return App::done('Items retrieved', ['items' => []]);
    }
}

Available API categories: - public - No authentication required - callback - Webhook/callback endpoint - systemApi - Internal system access - userApi - Authenticated user access - userWebhook - Authenticated user webhook

Cron Job Files

Cron files in Crons/ are PHP scripts executed by the PHPShift cron thread once per minute (or per schedule defined inside the file):

<?php

// Run at midnight
if (date('H:i') !== '00:00') exit;

// Cleanup expired sessions
DB::delete('sessions', 'expires_at < NOW()');

PHPShift manages cron execution through a Python background thread that calls php cron -auto every minute. You can start and stop cron processing from inside the skill menu under More > StartCrons and More > StopCrons.

The App Helper Class

App is a global PHP static utility class provided by the framework engine. Generated code uses it for all framework interactions:

| Method | Purpose | |--------|---------| | App::env($key) | Read .env variable | | App::done($msg, $data) | Return {"message": ..., "response": ..., "error": false} | | App::failed($msg) | Return {"message": ..., "error": true} | | App::info($msg, $data) | Return informational response | | App::error($msg) | Log a developer error | | App::lng($key, $text, $vars) | Return translated string |

All API responses follow the same JSON envelope so the front-end App.call() handler always knows what to expect.

Composer Plugins

Generated PHP code can require Composer packages. When PHPShift's AI detects a needed package (e.g., phpmailer/phpmailer), it includes it in config.json under composer-plugins. PHPShift then prompts you to confirm before running:

composer require phpmailer/phpmailer

The vendor/ directory and composer.json are both patch-tracked, so plugin installation can be rolled back if needed.

Environment Variables

All sensitive configuration is stored in .env and read via App::env(). Generated code uses this pattern to avoid hardcoding credentials:

$apiKey = App::env('STRIPE_API_KEY');

When the AI detects an App::env() call referencing a variable that doesn't exist in .env yet, PHPShift adds it automatically with an empty value and opens the file in VS Code for you to fill in.

AI Engine

The AI engine in PHPShift is the aisi Python module - a purpose-built skill runner that assembles context-rich prompts and communicates with AI models to generate structured file output.

How Skills Work

Each skill is a folder containing two files:

Some skills also have a readme.md describing the skill's purpose for developers.

Prompt Templates

Prompt files use double-bracket placeholders that are replaced with live project data before the prompt is sent to the AI:

[[MESSAGE]]          → The developer's natural language task description
[[databaseSchema]]   → Current MySQL schema (tables, columns, types)
[[databaseVersion]]  → MySQL server version string
[[files]]            → List of all Pages/, Apis/, Crons/ file paths
[[phpMethods]]       → All PHP public static methods tagged with (AI-USE)
[[jsMethods]]        → All JavaScript App object methods tagged with (AI-USE)
[[styling]]          → CSS from a developer-selected existing page
[[pages]]            → readme.md content from all existing pages
[[codeBase]]         → Full file contents of a target page
[[logContent]]       → Content of a selected log file
[[frameworkStructure]] → .system/ PHP framework directory listing
[[frameworkCodebase]]  → Core framework PHP file contents
[[frameworkSolvedIssues]] → Resolved issue notes from solved.md

These placeholders are populated by the Collectors class at runtime, ensuring the AI always has accurate, current information.

The Collectors Class

Collectors is a Python class in .system/collectors.py where each method corresponds to a named placeholder. The aisi module calls the appropriate collector method based on which placeholders appear in the skill's prompt.

For example, [[phpMethods]] triggers Collectors.phpMethods(), which:

  1. Walks every .php file in .system/
  2. Finds methods with /** (AI-USE) doc comments
  3. Extracts method signatures and documentation
  4. Returns a formatted PHP code block

This ensures the AI knows exactly which methods exist and how to use them - without you having to document anything extra.

AI Response Parsing

The AI responds with named file blocks in markdown format:

[readme.md]
```md
## Goal
Create a user registration page...
```

[page.html]
```html
<div class="register-form">
  ...
</div>
```

[code.php]
```php
class PageRegister {
  public function register($post = [], ...) {
    ...
  }
}
```

aisi parses these blocks, extracts each filename and content pair and writes them to disk. Binary or special files are handled accordingly.

Model Selection

PHPShift supports multiple AI providers through the AISI.models() selector. During phpshift new or More > ChangeAIModel, you pick a model from an interactive list. The model identifier and API key are stored in .env:

PHPSHIFT_AIMODEL="claude-3-5-sonnet-20241022"
PHPSHIFT_AIKEY="sk-ant-..."

For Google Vertex AI, the PHPSHIFT_AIKEY value is a relative path to a service account JSON file:

PHPSHIFT_AIMODEL="vertex/gemini-1.5-pro"
PHPSHIFT_AIKEY="credentials/service-account.json"

Skill Execution Flow

Developer selects skill + types task description
         ↓
AISI loads prompt.md for the selected skill
         ↓
AISI calls Collectors for each [[placeholder]] found
         ↓
Full prompt assembled with live project context
         ↓
Prompt sent to AI model (via configured API)
         ↓
AI returns structured file blocks
         ↓
AISI parses response, writes files to disk
         ↓
PHPShift shows result, prompts for confirmation

Skill Discovery

The main CLI menu is built dynamically by scanning the Create/, Edit/, Delete/, Read/, Render/, More/ and PHPShift/ directories for skill.py files. The menu structure mirrors the directory tree and options are filtered based on project state (e.g., "Edit API" is hidden if no APIs exist yet).

Database Layer

PHPShift manages MySQL databases through two layers: a Python-side DB module for CLI operations (schema inspection, patch rollback, session management) and a PHP-side ORM provided by the .system/ framework engine for runtime query execution.

Python DB Module

The DB class (modules/database.py) is used by PHPShift's CLI during the development session - not by the running PHP project. Its responsibilities include:

DB Patch System

Every time a skill is about to generate code that may run SQL, PHPShift calls DB.reserve() to begin a tracked transaction. If the developer accepts the changes, DB.clear() finalizes them. If they reject, DB.rollback() reverts all database mutations made during that skill run.

PHP Database ORM

At runtime, the PHP framework's .system/ engine provides a database abstraction layer accessed through static methods. Generated page and API code uses these exclusively - never raw PDO or mysqli.

Common patterns in generated PHP:

// Fetch records
$items = DB::select('SELECT * FROM tasks WHERE user = :uid', [':uid' => $userId]);

// Insert a record
$id = DB::insert('tasks', ['title' => $title, 'user' => $userId, 'created' => date('Y-m-d H:i:s')]);

// Update a record
DB::update('tasks', ['title' => $newTitle], 'id = :id', [':id' => $taskId]);

// Delete a record
DB::delete('tasks', 'id = :id', [':id' => $taskId]);

These methods are among the [[phpMethods]] collected by Collectors.phpMethods() and made available to the AI when generating code, ensuring correct usage every time.

System Tables

When a new project database is initialized, PHPShift runs setup.sql which creates these framework-level tables:

| Table | Purpose | |-------|---------| | user_files | Tracks user-uploaded file references (path, mime, token) | | user_keys | Stores named key-value pairs per user (sessions, tokens, settings) | | api | Manages registered API access tokens with expiry |

These tables are used by the framework engine itself. Your application tables are created by the db.sql files generated alongside your pages.

SQL Generation Rules

When PHPShift's AI generates SQL, it follows strict rules enforced in every prompt:

Read Skills for Database

The Read > Database skill lets you query your database using natural language during a development session. You describe what data you want and the AI generates a statement.sql and params.json which PHPShift then executes and displays inline. This is useful for debugging, inspecting data, or verifying that generated inserts worked correctly.

Pages Overview

Pages are the primary building block of a PHPShift project. Each page is a self-contained, full-stack unit: a folder containing HTML structure, CSS styles, JavaScript interactions, PHP business logic and a documentation file.

What a Page Is

A page in PHPShift corresponds to a single URL route in your application. When a visitor navigates to /dashboard, the framework routes the request to the Pages/private.dashboard/ folder and serves its HTML through code.php.

Pages are not templates or partials - each one is a complete, independently functional unit. However, they share:

  • Global assets from .assets/ (base CSS, global JS, jQuery, jQook)
  • PHP methods from .system/ (App helper, DB ORM, access control)
  • SEO metadata from Space/seo.html
  • Translation keys from Space/lng.*.json

Page Lifecycle

  1. AI generates the page via Create > Page or Render > Page
  2. Files are written to Pages/{group}.{name}/
  3. DB migration (db.sql) is optionally applied
  4. Access group method is auto-generated in .access if the group is new
  5. Developer confirms or rolls back
  6. Page is live at /{name} (not /{group}/{name})

Note: Pages are accessed by their name only in URLs - the group is invisible to visitors. /edititem not /public/edititem.

Page Files

| File | Required | Purpose | |------|----------|---------| | readme.md | Yes | AI-maintained documentation of page goal, functionality, usage | | code.php | Yes | PHP class with business logic methods (even if just an empty class) | | page.html | If needed | HTML structure (no <html>, <head>, or asset links) | | style.css | If needed | Scoped responsive styles for this page | | script.js | If needed | jQuery/jQook interaction logic | | db.sql | Temporary | MySQL migration - deleted after being applied | | config.json | Temp | Metadata used by PHPShift during generation - not stored permanently |

Access Groups

The {group} prefix in the folder name determines which users can access the page. Groups are defined as static methods in the .access PHP class:

class Access {
    public static function public() { return true; }
    public static function private() { return App::isLoggedIn(); }
    public static function admin() { return App::isAdmin(); }
}

When you create a page with a new group name, PHPShift detects that the group method doesn't exist and automatically runs the Render > Group skill to generate it.

The readme.md File

Every page's readme.md is AI-generated and AI-readable. It serves as:

  • Developer documentation you can read to understand the page
  • Context source - when editing or rendering a page, the [[pages]] collector reads all readme.md files to give the AI project-wide page awareness
  • Project overview source - if no README.md exists, the [[aboutProject]] collector assembles content from page readme files

Keep readme.md accurate - it's the AI's memory of what each page does.

Page Structure

Understanding the internal structure of a PHPShift page helps you navigate generated code, make manual adjustments and know how the PHP and JavaScript layers communicate.

HTML (page.html)

The HTML file contains only the body content of the page - no <!DOCTYPE html>, <html>, <head>, or <body> tags. The framework injects those automatically along with:

  • jQuery CDN link
  • jQook CDN link
  • Page-specific style.css
  • Page-specific script.js
  • Global .assets/style.css
  • Global .assets/script.js
  • SEO metadata from Space/seo.html

Images reference /assets/default.png, videos /assets/default.mp4, audio /assets/default.mp3.

Font Awesome free icons are available in HTML (the framework includes them).

Example HTML structure:

<div class="hero-section">
  <h1 translate="hero_title">Welcome to MyApp</h1>
  <p translate="hero_subtitle">The fastest way to manage your tasks.</p>
  <button id="cta-btn">Get Started</button>
</div>

The translate attributes are added by the Create > Translation skill to mark strings for multilingual support.

CSS (style.css)

Styles are scoped to the page and generated to match existing pages' design language. When creating a new page, PHPShift asks which existing page to use as a styling example - the AI receives that page's CSS and replicates its design system.

Generated CSS is fully responsive and avoids inline styles.

JavaScript (script.js)

Page JavaScript uses jQuery and the global App JavaScript object. The key communication method is App.call():

App.call('dashboard', 'getStats', {}, (echo) => {
    if (echo.error) {
        App.alert(echo.message, 'error');
        return;
    }
    $('#total-tasks').text(echo.response.stats[0].total);
});

App.call(url, method, data, callback): - url - page name (maps to Pages/public.{url}/) - method - public method name in the page's PHP class - data - object sent as POST body - callback - receives echo object: {message, response, error}

Translation strings in JS use App.lng():

const label = App.lng('save_button', 'Save Changes');

PHP (code.php)

The PHP class handles all server-side logic. It is named with the page name in PascalCase with the Page prefix:

class PageDashboard
{
    // Called via App.call('dashboard', 'getStats', {...}, callback)
    public function getStats($post = [], $get = [], $files = [])
    {
        // Validate inputs, query database, return response
        return App::done('Stats loaded', ['count' => 42]);
    }

    private function validateUser($userId)
    {
        // Private helpers are not callable from JS
    }
}

Rules enforced by the AI: - All JS-callable methods are public - Arguments are always ($post = [], $get = [], $files = []) - Input validation is always included - Environment variables are read via App::env('KEY_NAME') - Redirects are never done in PHP - always via JavaScript

Front-End / Back-End Communication Flow

User action in browser
    ↓
script.js: App.call('pagename', 'methodName', data, callback)
    ↓
Framework routes POST to Pages/group.pagename/code.php → PagePagename::methodName()
    ↓
PHP processes → returns App::done(message, response)
    ↓
callback(echo) in script.js receives { message, response, error }
    ↓
JS updates the DOM

No separate REST endpoints are needed for page-level interactions - the App.call() system handles PHP method dispatch transparently.

Access Groups

Access groups are PHPShift's authorization system for pages. Every page belongs to a group and the group determines which users can access it.

How Groups Work

The group is the first part of a page's folder name: Pages/{group}.{name}/. The framework checks the corresponding static method in the .access PHP class before serving any page:

class Access
{
    public static function public()
    {
        // Everyone can access 'public' pages
        return true;
    }

    public static function private()
    {
        // Only logged-in users can access 'private' pages
        return App::isLoggedIn();
    }

    public static function admin()
    {
        // Only admin users
        return App::isAdmin() && App::isLoggedIn();
    }
}

If the access method returns false, the framework redirects or returns a 403 response.

Default Groups

| Group | Typical Use | |-------|------------| | public | Pages accessible to all visitors (landing, login, signup) | | private | Pages for authenticated users only (dashboard, profile) | | admin | Pages for administrators only | | callback | Webhook receiver endpoints (no standard auth) |

You can define any group name - the AI respects whatever name you use.

Auto-Generated Group Methods

When the AI creates a page with a group that doesn't have an existing method in .access, PHPShift automatically runs the Render > Group skill. This skill:

  1. Receives the new group name and a description of what the group means
  2. Generates the appropriate static method in .access

For example, creating a page with group premium triggers generation of:

public static function premium()
{
    // Premium means only subscribed users with active premium plan can access
    return App::isLoggedIn() && App::env('USER_PLAN') === 'premium';
}

The description used to generate this method comes from the group-description field in config.json that the AI populates when creating the page:

{
    "page-group": "premium",
    "group-description": "premium - means that only subscribed users with an active premium plan can access the page"
}

Checking Groups in Your PHP Code

Within page PHP code, you don't need to manually check group access - the framework handles it before your class is even instantiated. However, if you need to verify access inside a method (e.g., for an App.call() request), use the App helper:

public function getPrivateData($post = [], $get = [], $files = [])
{
    if (!App::isLoggedIn()) {
        return App::failed('Unauthorized');
    }
    // ...
}

Editing the Access Class

The Edit > Access skill lets you modify the .access file using AI. Describe what you need ("add a moderator group that requires the user to have role='mod' in the database") and PHPShift updates the class while preserving existing group methods.

APIs Overview

PHPShift supports standalone REST API files for endpoints that operate independently of pages - webhooks, mobile app backends, external integrations and internal system services.

When to Use APIs vs Page Methods

Use App.call() page methods when: - The front-end JavaScript on the same page is the caller - The interaction is tightly coupled to a specific page - You're building CRUD operations for that page's data

Use API files when: - The caller is external (mobile app, third-party service, webhook) - Multiple pages or services need the same endpoint - You need versioned API routes (v1, v2) - You're building a public API with token authentication

API File Location and Naming

API files live in Apis/ and follow strict naming:

Apis/
├── v1.getItems.php
├── v1.createItem.php
├── v2.getItems.php
└── v1.processWebhook.php
  • Version prefix: v1, v2, etc.
  • Name: camelCase
  • Full name format: {version}.{camelCaseName}.php

API URL Routing

The framework routes API calls automatically. An API file v1.getItems.php is accessible at:

GET /api/v1/getItems

The router parses the version and name from the URL and dispatches to the correct file.

Access Categories

Each API file declares its category (access control) and allowed HTTP method on the first line:

<?php category('public', 'GET');

| Category | Who Can Call | |----------|-------------| | public | Anyone without authentication | | callback | Webhook/callback source with verification | | systemApi | Internal system (server-to-server) | | userApi | Authenticated users with valid API token | | userWebhook | Authenticated user webhook with token |

Response Format

All API responses use the same JSON envelope as page methods:

{
    "message": "Items retrieved successfully",
    "response": [...],
    "error": false
}

Use App::done(), App::failed(), or App::info() to produce these - never echo json_encode() directly.

Managing APIs

| Action | Skill | |--------|-------| | Create a new API | Create > API | | Edit an existing API | Edit > API | | Delete an API | Delete > API |

PHPShift's skill menu dynamically shows or hides Edit/Delete API options depending on whether any API files currently exist in Apis/.

API Structure

Every PHPShift API file follows a strict structure enforced by AI generation rules and the framework's dispatch engine.

Full API File Example

// Specify API category and allowed HTTP method
<?php category('userApi', 'POST');

/**
 * Required parameters:
 * - $json['item_id'] (int) - ID of item to update
 * - $json['title']   (string) - New item title
 */

// Class name: 'Api' prefix + PascalCase name
class ApiUpdateItem
{
    // Entry point - always 'init', always these three arguments
    public function init($json = [], $post = [], $get = [])
    {
        $itemId = (int)($json['item_id'] ?? 0);
        $title  = trim($json['title'] ?? '');

        if (!$itemId || !$title) {
            return App::failed('Invalid parameters');
        }

        $updated = DB::update('items', ['title' => $title], 'id = :id', [':id' => $itemId]);
        if (!$updated) {
            return App::failed('Update failed');
        }

        return App::done('Item updated', ['item_id' => $itemId]);
    }

    private function validateOwnership($itemId, $userId)
    {
        $item = DB::query('SELECT user FROM items WHERE id = :id', [':id' => $itemId]);
        return !empty($item) && $item[0]['user'] === $userId;
    }
}

Naming Rules

| Element | Rule | Example | |---------|------|---------| | File name | {version}.{camelCase}.php | v1.updateItem.php | | Class name | Api + PascalCase of name | ApiUpdateItem | | Entry method | Always init | public function init(...) | | Helper methods | private | private function validateOwnership(...) |

Parameter Sources

The init method receives three arguments:

  • $json - JSON body (for POST/PUT requests with Content-Type: application/json)
  • $post - Form POST fields
  • $get - URL query string parameters

Always validate and sanitize all inputs before using them.

Return Methods

| Method | Use When | |--------|---------| | App::done($msg, $data) | Success with data | | App::failed($msg) | Business logic failure (not a server error) | | App::info($msg, $data) | Informational response | | App::error($msg) | Log a developer-facing error (does not return to caller) |

Calling APIs from External Clients

From a mobile app or external service, call the API endpoint directly:

POST https://myapp.com/api/v1/updateItem
Content-Type: application/json
X-System: {api_token}

{
    "item_id": 42,
    "title": "New Title"
}

The X-System header is used for API token authentication in userApi and systemApi categories. The framework's token validation is handled automatically before your init() method is called.

Calling APIs from Within the Project's JavaScript

For API endpoints that your own front-end JavaScript calls, you can use App.call() pointing to the API path:

App.call('api/v1/updateItem', 'init', {item_id: 42, title: 'New Title'}, (echo) => {
    if (!echo.error) console.log('Updated!');
});

However, for page-level interactions, generating a page method (via Create > Page or Edit > Page) is preferred over separate API files.

Cron Jobs Overview

PHPShift includes a built-in cron job management system that runs scheduled PHP scripts in the background during your development session - and on your production server via a standard system cron.

What Cron Jobs Are For

Cron jobs are background tasks that run on a schedule, independent of user requests. Common uses in PHPShift projects:

  • Sending scheduled email digests or notifications
  • Cleaning up expired sessions, tokens, or temporary files
  • Syncing data from external APIs
  • Generating reports or aggregating statistics
  • Processing queued background jobs

Cron File Location

Cron files live in Crons/:

Crons/
├── sendDigest.php
├── cleanExpired.php
└── syncPrices.php

How PHPShift Executes Crons

During a development session (phpshift start), if cron files exist, PHPShift asks "Want to start cron jobs?" A Python background thread is started that fires:

php cron -auto

once every minute. The cron entry point file (at project root) reads all files in Crons/, determines which ones should run based on their internal time checks and executes them.

You can manually control cron execution from the skill menu:

  • More > StartCrons - Start the background cron thread
  • More > StopCrons - Stop the background cron thread

Production Cron Setup

On your production server, set up a system cron to call the same entry point:

* * * * * php /var/www/myapp/cron -auto

The cron files themselves contain internal schedule logic (e.g., only run at midnight), so running cron -auto every minute is safe - each job self-determines whether it's time to execute.

Managing Cron Jobs

| Action | Skill | |--------|-------| | Create a new cron job | Create > CronJob | | Edit an existing cron job | Edit > CronJob | | Delete a cron job | Delete > CronJob |

The skill menu shows Edit/Delete Cron options only when cron files exist in Crons/.

Cron Job Structure

PHPShift cron files are PHP scripts that run autonomously. They have direct access to the full framework - database ORM, App helpers, environment variables - just like page PHP classes.

Basic Cron File

<?php

// Only run once per day at midnight
if (date('H:i') !== '00:00') exit;

// Clean up expired API tokens
$deleted = DB::delete('api', 'expires < :now AND expires > 0', [':now' => time()]);

if ($deleted) {
    App::error("Cleaned " . count($deleted) . " expired API tokens");
}

Cron File with Notifications

<?php

// Run every hour at :00
if (date('i') !== '00') exit;

// Get users with pending notifications
$users = DB::query(
    'SELECT u.email, COUNT(n.id) as count FROM notifications n 
     JOIN users u ON u.id = n.user 
     WHERE n.sent = 0 AND n.scheduled <= NOW() 
     GROUP BY u.id',
    []
);

foreach ($users as $user) {
    // Send notification email
    $mailer = new PHPMailer\PHPMailer\PHPMailer();
    // ... configure and send

    // Mark as sent
    DB::update('notifications', ['sent' => 1], 'user = :uid AND sent = 0', [
        ':uid' => $user['id']
    ]);
}

Naming Rules

| Element | Rule | Example | |---------|------|---------| | File name | camelCase .php | sendDigest.php | | No class required | Plain script | - | | Schedule logic | Internal if check | if (date('H:i') !== '00:00') exit; |

Unlike pages and APIs, cron files are not classes. They are plain PHP scripts executed directly by the cron runner.

Available Resources

Cron files have access to everything the framework provides:

// Read environment variables
$apiKey = App::env('EXTERNAL_API_KEY');

// Database queries
$records = DB::query('SELECT * FROM items WHERE ...', [...]);
DB::insert('logs', ['action' => 'cron_ran', 'time' => date('Y-m-d H:i:s')]);

// Translations (if needed for notification text)
$subject = App::lng('digest_subject', 'Your daily digest');

// Error logging
App::error('Something went wrong in cron: ' . $errorMessage);

Generating Cron Jobs with AI

The Create > CronJob skill generates a fully functional cron file. Describe what the job should do and when:

Every day at 2 AM, find all users who have not logged in for 30 days 
and send them a re-engagement email using PHPMailer

PHPShift provides the AI with your current database schema and available PHP methods, so generated cron code correctly references your actual table names and columns.

After generation, if the cron needs a Composer plugin (like PHPMailer), PHPShift installs it immediately.

Viewing Cron Logs

Cron jobs can write to log files in Space/. Use the Read > Log skill to have the AI analyze a log file and summarize errors or anomalies.

Create > Project

The Create > Project skill generates a complete structural plan for your web project: a README.md, a database schema (db.sql) and individual markdown description files for every page, API and cron job the AI determines is necessary.

What It Generates

Given a plain-language project description, the AI produces:

  1. README.md - Project overview: goal, pages, APIs, cron jobs and usage summary
  2. db.sql - Full MySQL schema with example records, ready to execute
  3. page/{group}/{name}.md - Description file for each page
  4. api/{version}.{name}.md - Description file for each API
  5. cron/{name}.md - Description file for each cron job
  6. config.json - Specifies the landing page

These markdown description files become blueprints - feed them one by one into Create > Page, Create > API and Create > CronJob to generate actual code.

When to Use It

Use Create > Project at the very start of a project to establish structure. It answers: "What pages, APIs and cron jobs does this project need?"

For adding major new sections to an existing project, use Edit > Project.

Example Task

A subscription recipe platform where users sign up, create and share recipes, 
comment on others' recipes and access premium recipes with a paid plan. 
Include admin moderation tools.

The AI produces a complete plan covering auth pages, recipe CRUD, commenting, subscription handling, admin tools and background cron jobs.

What It Does Not Do

This skill generates planning documents only - no PHP, HTML, CSS, or JavaScript is written and no database changes are applied. Actual code is generated per-unit via Create > Page etc.

After Creation

Review the generated README.md and description files. Edit them to better reflect your vision before using them as code-generation input. The richer the descriptions, the higher quality the generated code will be.

Create > Page

The Create > Page skill generates a complete, working full-stack page: HTML structure, CSS styles, JavaScript interactions, PHP business logic, a database migration and documentation.

Context the AI Receives

Before generating, PHPShift collects:

  • Current database schema and MySQL version
  • All existing page, API and cron file paths
  • All available PHP methods (from .system/ with AI-USE annotations)
  • All available JavaScript App object methods
  • CSS from an existing page (you choose which one as a styling reference)

This ensures new pages are consistent with your existing codebase.

Generated Files

| File | Always? | Purpose | |------|---------|---------| | readme.md | Yes | Page goal, functionality and usage docs | | code.php | Yes | PHP class with business logic (even if minimal) | | page.html | If needed | HTML body structure | | style.css | If needed | Page-specific responsive styles | | script.js | If needed | jQuery/jQook front-end logic | | db.sql | If needed | MySQL migration to apply immediately | | config.json | Yes | Page metadata (name, group, composer deps) |

Example Task

A private dashboard page showing the logged-in user's task count, 
recent activity feed and a quick-add task form

PHPShift sends the AI your database schema, existing PHP methods and a CSS example. The AI generates a complete dashboard page that uses your actual table names and PHP method signatures.

Styling Reference

When creating a page, PHPShift asks "Select styling example" - choose an existing page whose CSS design you want the new page to match. If no pages exist yet, you can skip this.

Access Group Auto-Generation

If your page uses a new access group (e.g., premium) that doesn't exist yet in .access, PHPShift automatically runs Render > Group to generate the access method.

Database Migrations

If the AI generates a db.sql file, PHPShift opens it in VS Code and asks for confirmation before applying it to the database. If you decline the changes at the review step, the database changes are rolled back automatically.

Create > API

The Create > API skill generates one or more PHP REST API files in Apis/. Use it when you need versioned endpoints callable from external clients (mobile apps, third-party services, webhooks).

Context the AI Receives

  • Current database schema and MySQL version
  • All existing file paths (pages, APIs, crons)
  • All available PHP methods from .system/

Generated Output

The AI produces one or more PHP files in the format v{version}.{camelCaseName}.php, each containing a properly structured API class.

Example Task

Create a v1 public API endpoint that returns a paginated list of public recipes, 
supporting optional category filter and keyword search via GET parameters

Output: Apis/v1.getRecipes.php

<?php category('public', 'GET');

class ApiGetRecipes
{
    public function init($json = [], $post = [], $get = [])
    {
        $page     = max(1, (int)($get['page'] ?? 1));
        $category = trim($get['category'] ?? '');
        $keyword  = trim($get['keyword'] ?? '');
        $limit    = 20;
        $offset   = ($page - 1) * $limit;

        $where  = 'r.public = 1';
        $params = [];

        if ($category) {
            $where .= ' AND r.category = :cat';
            $params[':cat'] = $category;
        }
        if ($keyword) {
            $where .= ' AND r.title LIKE :kw';
            $params[':kw'] = '%' . $keyword . '%';
        }

        $params[':limit']  = $limit;
        $params[':offset'] = $offset;

        $recipes = DB::query(
            "SELECT r.id, r.title, r.category, r.created 
             FROM recipes r WHERE {$where} 
             ORDER BY r.created DESC LIMIT :limit OFFSET :offset",
            $params
        );

        return App::done('Recipes retrieved', ['recipes' => $recipes, 'page' => $page]);
    }
}

Versioning

Always specify the version in your task description. The AI uses it as the file version prefix. When creating a v2 update to an existing endpoint, the original v1 file is untouched.

Composer Dependencies

If the generated API requires a Composer package, PHPShift detects it from config.json and prompts you to install it before confirming the skill run.

Create > CronJob

The Create > CronJob skill generates a PHP cron job script in Crons/. Cron jobs run on a schedule and handle background tasks independent of user requests.

Context the AI Receives

  • Current database schema and MySQL version
  • All existing project file paths
  • Available PHP methods from .system/

Generated Output

A single PHP file in Crons/ named in camelCase (e.g., cleanExpiredSessions.php). The file contains:

  • A time-check guard at the top to control when it runs
  • Business logic using the full framework DB ORM and App helpers
  • Proper error logging

Example Task

Every day at 3 AM, delete sessions from the sessions table that expired 
more than 7 days ago and log the count of deleted records

Output: Crons/cleanExpiredSessions.php

<?php

if (date('H:i') !== '03:00') exit;

$cutoff  = date('Y-m-d H:i:s', strtotime('-7 days'));
$deleted = DB::delete('sessions', 'expires_at < :cutoff', [':cutoff' => $cutoff]);

App::error("Cleaned expired sessions. Count: " . ($deleted ? 'success' : '0'));

Schedule Examples

Describe your schedule in natural language - the AI translates it to PHP time-check logic:

| Description | Generated guard | |-------------|----------------| | Every minute | (no guard - runs every invocation) | | Every hour | if (date('i') !== '00') exit; | | Every day at midnight | if (date('H:i') !== '00:00') exit; | | Every Monday at 8 AM | if (date('D H:i') !== 'Mon 08:00') exit; | | First day of month | if (date('d H:i') !== '01 00:00') exit; |

Composer Dependencies

If the cron job needs a package (e.g., phpmailer/phpmailer for email), PHPShift detects it from config.json and installs it before confirming.

After Creation

The cron file is immediately executable. If the PHPShift cron thread is running (More > StartCrons), it will be picked up within the next minute cycle. You can also test it manually:

php cron sendDigest

Create > Translation

The Create > Translation skill adds full multi-language support to an existing page in one operation. It modifies HTML, CSS, JavaScript and PHP files to integrate translation tags, then generates the translation JSON file for the requested language.

What It Does

Given a page and a target language, the AI:

  1. Updates page.html - Adds a <translation languages="en,{lang}"> tag to the page (or appends the new language to an existing one). Adds translate="{key}" attributes to all hardcoded text elements.

  2. Updates style.css - Adds translation and translation img CSS rules for the language switcher UI component.

  3. Updates script.js - Wraps hardcoded strings in App.lng(key, text) calls.

  4. Updates code.php - Wraps PHP hardcoded strings in App::lng(key, text) calls.

  5. Creates Space/lng.{lang}.json - The translation file containing all key-value pairs for the requested language.

Example Task

Add Georgian (ka) translation to the dashboard page

Translation Key Format

Keys are unique, descriptive and lowercase with underscores:

<h1 translate="dashboard_title">My Dashboard</h1>
<button translate="add_task_btn">Add Task</button>
// Space/lng.ka.json
{
    "dashboard_title": "ჩემი სამუშაო მაგიდა",
    "add_task_btn": "დავალების დამატება"
}

Dynamic Translations

For strings with variables, the {variable} syntax is used:

App.lng('welcome_msg', 'Hello, {name}!', {name: username});
{ "welcome_msg": "გამარჯობა, {name}!" }

Adding More Languages

Run Create > Translation again with a different language code. The skill detects the existing <translation> tag and appends the new language abbreviation to its languages attribute.


Create > SEO

The Create > SEO skill generates Space/seo.html - the project-level SEO metadata file included in every page's <head>.

What It Generates

A complete HTML snippet containing:

  • Open Graph meta tags (og:title, og:description, og:image, og:url)
  • Twitter Card tags
  • Standard description and keyword meta tags
  • Canonical URL
  • Structured data (JSON-LD) where applicable

Example Task

SEO for a recipe sharing platform called "RecipeHub" targeting home cooks, 
using the share.png image and focusing on keywords around easy recipes and cooking tips

Note

The SEO file is shared across all pages. Page-specific SEO overrides should be set dynamically in individual code.php files using framework SEO helpers.


Create > README

The Create > README skill generates or regenerates README.md at the project root. It reads your existing pages' readme.md files and the project .md briefing to produce a comprehensive, professional readme.

What It Generates

  • Project title and description
  • Features list
  • Tech stack
  • Setup instructions
  • Page/API overview
  • Usage examples

When to Use

  • After completing an initial set of pages
  • Before publishing to GitHub
  • After major feature additions via Edit > Project

Create > LICENSE

The Create > LICENSE skill installs a license file at the project root. PHPShift includes a library of common open source licenses and lets you select one interactively.

Available Licenses

  • MIT License
  • Apache Software License 2.0
  • GNU General Public License v3 (GPLv3)
  • GNU Affero General Public License v3
  • GNU Lesser General Public License v3
  • Mozilla Public License 2.0
  • BSD License
  • ISC License

The selected license is populated with your project author name (from PROJECT_AUTHOR in .env) and the current year.

Note

This skill is only shown in the menu if no LICENSE file exists yet. Once a license is installed, use Edit > LICENSE to change it or Delete > LICENSE to remove it.

Create > SEO

The Create > SEO skill generates Space/seo.html - the project-level SEO metadata file included in every page's <head>.

What It Generates

A complete HTML snippet containing:

  • Open Graph meta tags (og:title, og:description, og:image, og:url)
  • Twitter Card tags
  • Standard <meta name="description"> and keyword tags
  • Canonical URL tag
  • JSON-LD structured data where relevant

Example Task

SEO for a recipe platform called "RecipeHub" targeting home cooks. 
Keywords: easy recipes, cooking tips, meal planning. 
Use share.png as the social image.

File Location

Space/seo.html is automatically included in every page's <head> by the framework. There is no need to reference it manually.

Project vs. Page SEO

This file sets global defaults for all pages. For page-specific SEO overrides (different title, different description per page), use PHP App helper methods inside individual code.php files to dynamically override the meta tags for that route.

After Creation

Preview the SEO output by inspecting <head> in your browser on any page. The Space/seo.html file is editable manually or via the Edit > SEO skill.

Sitemap

The framework auto-generates Space/sitemap.xml with the current date when pages are added. The .htaccess serves it at /sitemap.xml automatically.

Create > README

The Create > README skill generates a professional README.md at the project root. It reads your project's existing page documentation files and the .md briefing to produce a comprehensive developer-facing readme.

What It Generates

  • Project title, description and tagline
  • Feature highlights
  • Technology stack overview (PHP, MySQL, jQuery, jQook)
  • Local setup instructions
  • Pages and API route overview
  • Usage examples

When to Use

  • After completing your initial set of pages and APIs
  • Before publishing the repository to GitHub or GitLab
  • After adding major new functionality via Edit > Project

Context the AI Uses

The skill reads: - Your .md project briefing file - readme.md files from all existing pages - Project metadata from .env (name, author, production domain)

Note

This skill is only shown if no README.md exists yet. Once created, use Edit > README to update it or Delete > README to remove it.

Create > LICENSE

The Create > LICENSE skill installs a license file in your project root from PHPShift's built-in license library.

Available Licenses

  • MIT License
  • Apache Software License 2.0
  • GNU General Public License v3 (GPLv3)
  • GNU Affero General Public License v3 (AGPLv3)
  • GNU Lesser General Public License v3 (LGPLv3)
  • Mozilla Public License 2.0 (MPL 2.0)
  • BSD License
  • ISC License (ISCL)

What It Does

PHPShift presents an interactive selection menu. After you choose a license:

  1. The license template is read from PHPShift's internal licenses/ directory
  2. {{year}} is replaced with the current year
  3. {{author}} is replaced with PROJECT_AUTHOR from your .env
  4. The file is written to {project}/LICENSE

Example

Selecting MIT License with PROJECT_AUTHOR="Jane Doe" and current year 2025 produces:

MIT License

Copyright (c) 2025 Jane Doe

Permission is hereby granted, free of charge, to any person obtaining a copy...

Visibility in Menu

This skill only appears in the menu when no LICENSE file exists. After creation, the menu switches to Edit > LICENSE and Delete > LICENSE.

Edit > Project

The Edit > Project skill updates an existing project plan when you need to add, change, or remove features across multiple pages. It works like Create > Project but with full awareness of what already exists.

Context the AI Receives

  • Descriptions of all existing pages (from their readme.md files)
  • Current database schema and MySQL version

What It Generates

  1. strategy.md - A strategic overview of what needs to change and why
  2. db.sql (if schema changes are needed) - Ready-to-execute migration SQL
  3. {group}.{page}.md description files for pages that need updates

Example Task

Add a social features layer: users should be able to follow each other, 
like recipes and see a social feed of activity from people they follow

The AI analyzes your existing pages and generates targeted update descriptions only for pages that need to change, plus the new pages/APIs required.

After Generation

Use the generated .md description files as input for Edit > Page on each affected page to generate the actual code changes.

Edit > Page

The Edit > Page skill modifies an existing page. It receives the full current codebase of the target page and regenerates only the files that need to change.

Context the AI Receives

  • Full contents of the target page's existing files (page.html, style.css, script.js, code.php)
  • Current database schema and MySQL version
  • All available PHP methods
  • All available JavaScript App methods
  • CSS styling example

How to Use

  1. Select Edit > Page from the menu
  2. Choose which page to edit from the list
  3. Describe what needs to change

PHPShift sets the VAR.target variable to the selected page folder so the [[codeBase]] collector loads the right files.

Example Task

Add a search and filter bar to the top of the page that filters the task list 
in real-time by title and status without page reload

The AI receives your existing page code and generates updated versions of only the files that need modification - leaving unchanged files intact.

Iterative Refinement

The Edit > Page loop supports multi-turn refinement. If you select Redo, PHPShift asks you to adjust your description and retries. You can specify what was wrong:

The filter works but the results don't clear when I delete my search text. 
Also the status dropdown styling doesn't match the rest of the page.

What Can Be Edited

  • Any combination of HTML, CSS, JS, PHP on an existing page
  • Database schema (via new db.sql if tables need changes)
  • Access group logic (by adjusting config.json group settings)
  • Composer dependencies (PHPShift installs new ones automatically)

Edit > API

The Edit > API skill modifies an existing API file. Select the API file to edit and describe what needs to change - the AI rewrites it with full awareness of your current database schema and available PHP methods.

Example Task

Add pagination support to v1.getRecipes.php - accept 'page' and 'per_page' 
GET parameters, return total count alongside the results

Menu Visibility

This option is only shown when at least one API file exists in Apis/.

Edit > CronJob

The Edit > CronJob skill modifies an existing cron job file. Select the cron to edit and describe the required changes - the AI updates the schedule logic, database queries, or notification logic as needed.

Example Task

Change the digest cron to run at 9 AM instead of midnight, 
and add a check to skip users who have unsubscribed from email notifications

Menu Visibility

This option is only shown when at least one cron file exists in Crons/.

Edit > Translation

The Edit > Translation skill updates an existing translation - either correcting translation values in a lng.*.json file, adding new keys, or updating translated strings across multiple pages.

Example Task

Update the Georgian translation file to translate the new task status labels 
we added to the dashboard page last session

What It Updates

  • Existing Space/lng.{lang}.json files
  • HTML translate attributes on pages that have new untranslated text
  • JavaScript and PHP lng() calls for new hardcoded strings

Edit > SEO

The Edit > SEO skill updates Space/seo.html. Use it when your project name, description, keywords, or social image changes - or when you want to add JSON-LD structured data.

Example Task

Update the SEO to reflect our new product name "RecipeVault" and 
add recipe schema JSON-LD structured data

Menu Visibility

Only shown when Space/seo.html has been initialized (via Create > SEO).

Edit > README

The Edit > README skill regenerates or updates the project's README.md. Use it after adding major features, changing the project scope, or before a public release to ensure the readme reflects the current state of the project.

Example Task

Update the readme to include the new API endpoints we added and 
expand the setup section with database migration instructions

Edit > Access

The Edit > Access skill modifies the .access PHP class - the file that defines page access group authorization methods.

What It Does

The AI receives the current .access content and the edit request, then generates an updated version of the file that adds, modifies, or removes group methods.

Example Tasks

Add a 'moderator' group that requires the user to have role='mod' in the users table
Update the 'premium' group check to also verify the subscription hasn't expired

Important Note

Every static method in .access corresponds to an access group used by pages in Pages/{group}.{name}/. Removing a group method will break all pages that use that group. PHPShift does not automatically check for this - review your page folders before deleting groups.

Delete > Page

Removes a page and all its associated files from the project.

What Gets Removed

The entire Pages/{group}.{name}/ folder including page.html, style.css, script.js, code.php and readme.md.

Process

  1. PHPShift lists all existing pages
  2. You select the page to delete
  3. Confirm the action
  4. The folder and all its contents are removed
  5. A Git commit opportunity is offered

Rollback

File deletions are tracked by the patch system. If you decide to undo before ending the session, roll back via the Redo option.

Database Tables

Deleting a page does not drop associated database tables. If you want to clean up tables, use Read > Database to run the appropriate DROP queries.

Menu Visibility

Only shown when custom pages exist (the default public.phpshift page is excluded).

Delete > API

Removes an API file from Apis/.

Process

  1. PHPShift lists all existing API files
  2. You select which one to remove
  3. The .php file is deleted

Note

This does not remove associated database tables. Use Read > Database for cleanup SQL if needed.

Menu Visibility

Only shown when at least one API file exists in Apis/.

Delete > CronJob

Removes a cron job file from Crons/.

Process

  1. PHPShift lists all existing cron files
  2. You select which one to remove
  3. The .php file is deleted

If the cron thread is running, the removed job will simply not be found on the next execution cycle.

Menu Visibility

Only shown when at least one cron file exists in Crons/.

Delete > Translation

Removes a language translation JSON file from Space/.

What Gets Removed

The Space/lng.{lang}.json file for the selected language. Translation tag references in HTML pages are not automatically cleaned up - you may want to run Edit > Page on affected pages to remove the unused language from <translation languages="..."> tags.

Menu Visibility

Only shown when at least one lng.*.json file exists in Space/.

Delete > Log

Removes a log file from Space/.

Process

PHPShift lists all *.log files in Space/. You select which one to delete and confirm.

When to Use

Log files can grow large. Clear them after reviewing issues (via Read > Log) or before production deployments.

Menu Visibility

Only shown when at least one .log file exists in Space/.

Delete > README

Removes the README.md file from the project root.

When to Use

  • Before regenerating with Create > README from scratch
  • When the project is private and a readme is unnecessary

Menu Visibility

Only shown when README.md exists. After deletion, the menu shows Create > README instead.

Delete > LICENSE

Removes the LICENSE file from the project root.

When to Use

  • Before switching to a different license (delete + Create > LICENSE)
  • For private projects that don't need a license

Menu Visibility

Only shown when a LICENSE file exists. After deletion, the menu shows Create > LICENSE instead.

Read > Database

The Read > Database skill lets you query your project's MySQL database using plain English. The AI translates your request into a SQL statement and parameters, executes them and displays the results - no SQL knowledge required.

How It Works

  1. You describe the data you want
  2. The AI receives your current database schema and generates statement.sql + params.json
  3. PHPShift executes the query and displays the result inline in the terminal

Example Tasks

Show me the 10 most recently created users with their email and created date
Count how many tasks are in each status category
Find all recipes that have more than 5 comments and were created this month

Generated Files

The skill produces two temporary files before execution:

  • statement.sql - The MySQL query (no markdown, no comments - pure SQL)
  • params.json - Named parameters used in the query, or {} if none

Safety

The AI is instructed to generate safe, parameterized queries only. No raw string interpolation, no destructive operations unless explicitly and unambiguously requested.

Use Cases

  • Debugging: verify that generated inserts or updates worked correctly
  • Development: inspect data to understand what the AI-generated code is producing
  • Quick lookups: check a user record, count rows, or inspect a join without leaving the terminal

Note

This skill executes immediately - it does not go through the patch/rollback system since it is read-oriented. Destructive queries (DELETE, DROP, TRUNCATE) are possible if explicitly requested, so use care when describing your task.

Read > Git

The Read > Git skill translates natural language into Git CLI commands and executes them in your project directory. It handles any Git operation - from inspecting history to managing branches to configuring remotes.

How It Works

  1. You describe the Git operation you need
  2. The AI generates a single, ready-to-execute command.sh containing the appropriate Git command
  3. PHPShift runs it in your project directory and shows the output

Example Tasks

Show me the last 10 commits with their dates and messages
Create a new branch called feature/user-auth and switch to it
Show all files changed in the last commit
Revert the most recent commit but keep the file changes staged
Show the diff between main and the current branch

Generated Output

A single command.sh file containing one Git command:

git log --oneline --format="%h %ad %s" --date=short -10

Note

PHPShift's main workflow already handles git add, git commit and git push natively after every skill confirmation. Use Read > Git for everything else - branching, diffing, inspecting history, resetting, configuring remotes, etc.

The generated command runs in your project root (Help.cwd). Commands requiring credentials (push, pull, clone with auth) assume your Git config or SSH keys are already set up.

Read > Log

The Read > Log skill performs AI-powered analysis of your application's log files. It reads the log content and your description of what you're looking for, then produces a structured summary.md highlighting key issues, errors and anomalies.

How It Works

  1. PHPShift lists all *.log files in Space/
  2. You select the log file to analyze
  3. You describe what you're looking for (or ask for a general summary)
  4. The AI reads the log content and generates a summary.md report

Example Tasks

Find all 500 errors from the last hour and tell me what caused them
Summarize all database errors in this log
Are there any repeated failed login attempts? Show me the patterns.
Give me a general health summary of this log file

Generated Output

A summary.md report with:

  • Key events - Critical errors, warnings and important operations
  • Error patterns - Repeated issues grouped by type
  • Potential causes - AI interpretation of what went wrong
  • Actionable insights - Specific suggestions for investigation or fixes
  • Timeline - Chronological highlights if timestamps are present

Log File Location

Application log files should be written to Space/ in your project. For example, a cron job might write to Space/digest.log. Your PHP code writes to these files using standard PHP file I/O or the App::error() logging utility.

Menu Visibility

Only shown when at least one .log file exists in Space/.

Render > Page

The Render > Page skill re-renders an existing page from scratch - regenerating all its files while preserving the page's identity (name, group) and staying consistent with your current database schema and PHP method surface.

Difference from Edit > Page

| | Edit > Page | Render > Page | |--|------------|--------------| | Approach | Modifies specific parts of existing code | Regenerates all files from your description | | Starting point | Existing code is context | Existing readme.md is context | | Use when | Making targeted changes | Page code is outdated or needs a full rewrite | | Preserves | Most of the existing structure | Page name and group only |

Use Edit > Page for incremental improvements. Use Render > Page when a page's code has drifted too far from what you need and a clean regeneration makes more sense than patching.

How It Works

  1. You select the page to re-render from the list
  2. PHPShift loads the page's readme.md as the base description
  3. You can provide additional instructions to adjust the render
  4. The AI regenerates all page files fresh, using current DB schema, PHP methods and a styling reference

Example Task

Re-render the dashboard page with an updated layout - 
move the activity feed to the right sidebar and make the stats cards larger

Context the AI Receives

  • The page's existing readme.md (goal, functionality, usage)
  • Current database schema and MySQL version
  • All available PHP methods and JS App methods
  • CSS from a selected styling reference page
  • List of all project files

After Rendering

Review the regenerated files and confirm or roll back as usual. If you confirm, the old files are replaced by the fresh render.

Render > Group

The Render > Group skill generates a new static method in the .access PHP class for a page access group that doesn't exist yet.

When It's Called

This skill is usually called automatically by PHPShift - not manually. When Create > Page or Render > Page produces a config.json specifying a group that has no method in .access, PHPShift automatically runs Render > Group before finishing.

You can also run it manually if you want to pre-define an access group before creating pages that use it.

How It Works

PHPShift passes the group name and its group-description from config.json to the AI. The AI generates a new public static function {groupName}() method and appends it to the .access class.

Example

If config.json contains:

{
    "page-group": "subscriber",
    "group-description": "subscriber - means the user has an active paid subscription"
}

The generated method might be:

public static function subscriber()
{
    if (!App::isLoggedIn()) return false;
    $user = DB::query('SELECT plan FROM users WHERE id = :id', [':id' => App::userId()]);
    return !empty($user) && $user[0]['plan'] === 'subscriber';
}

Manual Use

Run Render > Group manually when you want to:

  • Define a new access group before any pages use it
  • Preview what the AI would generate for a group before committing to it
  • Update the group logic via Edit > Access reference

Note

The .access class is PHP. The static method names must match the group folder prefix exactly (case-insensitive matching may vary by server). Keep group names lowercase and simple.

Environment Variables

All PHPShift project configuration lives in the .env file at the project root. This file is never exposed publicly (.htaccess denies all access to it) and is excluded from Git via .gitignore.

System Variables (Framework)

These are set during phpshift new and managed by PHPShift:

| Variable | Description | Example | |----------|-------------|---------| | PROJECT_NAME | Human-readable project name | My Recipe App | | PROJECT_AUTHOR | Author name (used in LICENSE) | Jane Doe | | PROJECT_LOCAL | Local development domain | myapp.local | | PROJECT_PRODUCTION | Production domain | myapp.com | | PROJECT_LANDING | Default landing page group/name | public/welcome | | PROJECT_KEY | Auto-generated secure app key | (random token) | | PHPSHIFT_AIMODEL | AI model identifier string | claude-3-5-sonnet-20241022 | | PHPSHIFT_AIKEY | AI API key or key file path | sk-ant-... | | DB_HOST | MySQL host | localhost | | DB_NAME | MySQL database name | myapp_db | | DB_USER | MySQL username | root | | DB_PASS | MySQL password | secret | | PRODUCTION | Production mode flag (1 or 0) | 0 | | ALLOWED | Comma-separated allowed IPs (dev restriction) | 127.0.0.1 |

Project Variables (Your App)

Below the ## Project comment section, PHPShift and the AI add custom variables as your project needs them. For example:

STRIPE_SECRET_KEY=""
SMTP_HOST=""
SMTP_PORT=""
SMTP_USER=""
SMTP_PASS=""

These are added automatically when generated PHP code contains App::env('VARIABLE_NAME') calls - PHPShift detects new variable names and appends them as empty entries, then opens the file in VS Code for you to fill in.

Reading Variables in PHP

$key = App::env('STRIPE_SECRET_KEY');
$host = App::env('SMTP_HOST');

Reading Variables in Python (PHPShift CLI)

model = Help.getEnv('PHPSHIFT_AIMODEL')
Help.setEnv('PHPSHIFT_AIMODEL', 'new-model-name')

Production Mode

Set PRODUCTION="1" on your live server to enable production behaviors:

Security

AI Models

PHPShift is model-agnostic - it supports any AI provider available through the aisi module. You choose your model during project creation and can switch at any time.

Selecting a Model

During phpshift new, you are presented with an interactive model selection list. The list is populated by AISI.models() from your installed aisi package.

To switch models during an active session, use More > ChangeAIModel. This updates PHPSHIFT_AIMODEL and PHPSHIFT_AIKEY in .env and reinitializes the AI connection immediately - no restart needed.

API Key Models

For most providers (Claude, OpenAI-compatible, etc.), configuration is straightforward:

PHPSHIFT_AIMODEL="claude-3-5-sonnet-20241022"
PHPSHIFT_AIKEY="sk-ant-api03-..."

The model string format depends on the provider. Refer to the aisi documentation for supported model identifiers.

Google Vertex AI

Vertex AI uses a service account JSON key file instead of a plain API key:

PHPSHIFT_AIMODEL="vertex/gemini-1.5-pro"
PHPSHIFT_AIKEY="credentials/vertex-key.json"

The key file path is relative to your project root. PHPShift checks that this file exists before starting a session. If it's missing, the session won't start and you'll see "AI key file not found!"

Store your Vertex credentials file in your project directory but add it to .gitignore to prevent accidental commits.

Choosing the Right Model

PHPShift skills send large prompts with significant code context. For best results:

Model Performance Notes

Changing the Model

More > ChangeAIModel

PHPShift shows the model selection list, then asks for the new API key. Both values are updated in .env and the AISI instance is reinitialized in the current session.

Localhost Setup

PHPShift automates local development server configuration using XAMPP on Windows. When you run phpshift start, it sets up everything needed to access your project via a custom .local domain - no manual Apache or hosts file editing required.

What PHPShift Configures

1. Windows Hosts File

PHPShift adds an entry to C:/Windows/System32/drivers/etc/hosts:

# phpshift_myapp-hosts
127.0.0.1 myapp.local
# phpshift_myapp-host

The comment markers (# phpshift_myapp-hosts and # phpshift_myapp-host) are used to identify and remove this entry cleanly when the project is stopped.

2. Apache Virtual Host

PHPShift adds a virtual host block to C:/xampp/apache/conf/extra/httpd-vhosts.conf:

# phpshift_myapp-vhost
<VirtualHost *:80>
    DocumentRoot "C:/projects/myapp"
    ServerName myapp.local
    <Directory "C:/projects/myapp">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Again, the comment marker (# phpshift_myapp-vhost) allows PHPShift to locate and remove this block cleanly on stop.

3. XAMPP Start

If Apache and MySQL are not already running, PHPShift starts them by executing:

C:/xampp/xampp_start.exe

Checking Localhost Status

PHPShift checks whether a project's localhost is already configured by:

  1. Verifying that httpd.pid and mysql.pid exist (XAMPP running)
  2. Finding the project's virtual host marker in httpd-vhosts.conf
  3. Finding the project's host marker in hosts

If all three conditions are met, the start step is skipped (fast startup for already-configured projects).

Stopping Localhost

When you exit PHPShift (phpshift stop or menu exit), it:

  1. Removes the virtual host block from httpd-vhosts.conf
  2. Removes the hosts entry from the Windows hosts file
  3. Optionally restarts Apache to apply the changes

Multiple Projects

Each PHPShift project uses a unique marker tag (phpshift_{hint}) based on the local domain name. Multiple projects can coexist with separate virtual hosts. Stopping one project does not affect others.

Port Configuration

PHPShift uses port 80 by default (standard HTTP). If another service occupies port 80, you'll need to adjust XAMPP's Apache port configuration manually in C:/xampp/apache/conf/httpd.conf before starting PHPShift.

Troubleshooting

XAMPP not found - Ensure XAMPP is installed at exactly C:/xampp. Custom paths are not currently supported without modifying the localhost.py module.

Permission denied on hosts file - PHPShift requires admin privileges to write to the Windows hosts file. Run your terminal as Administrator when starting PHPShift.

Virtual host not loading - Ensure Apache's httpd-vhosts.conf include is uncommented in httpd.conf. Look for Include conf/extra/httpd-vhosts.conf and make sure it's not commented out.

Database Configuration

PHPShift uses MySQL (via XAMPP) for local development. All database connection details are stored in .env and managed through PHPShift's DB module.

Connection Variables

DB_HOST="localhost"
DB_NAME="myapp_db"
DB_USER="root"
DB_PASS="your_password"

These are set during phpshift new and used by both the Python CLI layer (for schema inspection and patch management) and the PHP framework layer (for runtime query execution).

Database Initialization

On first phpshift start, if the database doesn't exist, PHPShift creates it automatically by running setup.sql:

CREATE DATABASE IF NOT EXISTS `myapp_db` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE `myapp_db`;
-- Creates system tables: user_files, user_keys, api

Handling Existing Databases

If DB_NAME in .env is wrapped in brackets (e.g., [myapp_db]), PHPShift treats it as "not yet confirmed" and checks whether the database exists when starting. If it does, you're prompted:

This prevents accidental data loss when switching between project states.

Database Schema Awareness

PHPShift continuously provides the AI with your current schema via DB.schema()[[databaseSchema]]. This means:

Database Migrations

When a skill generates a db.sql file, PHPShift:

  1. Writes the file to the page folder temporarily
  2. Opens it in VS Code so you can review it
  3. Asks "Confirm to update database" before running it
  4. Applies it via DB.submit() if confirmed
  5. Deletes the .sql file after successful application

If the skill run is rejected (Redo or No), the database changes are rolled back via DB.rollback().

Exporting the Schema

Use More > ExportDatabaseSchema to export your current database schema as a SQL file. Useful for:

Production Database

For production, update .env on your server with the production database credentials. Set PRODUCTION="1" to enable production mode. PHPShift itself is not deployed to production - only the PHP framework and your project files are.

Character Set

All PHPShift databases use utf8mb4 with utf8mb4_general_ci collation by default, ensuring full Unicode support including emoji.

Security Overview

PHPShift bakes security into the generated framework from day one. The .htaccess file, PHP framework engine and environment variable system all enforce protections that would take significant effort to implement manually in a typical PHP project.

Security Layers

1. Apache-Level (.htaccess)

Every PHPShift project is initialized with a security-hardened .htaccess that:

2. PHP Framework Engine

The .system/ PHP engine:

3. Generated Code Practices

The AI generation prompts enforce:

What PHPShift Does Not Handle

HTAccess Rules

The .htaccess file generated by PHPShift is a security-first Apache configuration. Every project starts with this hardened baseline - no manual setup required.

HTTP Security Headers

Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "no-referrer"
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header set Access-Control-Allow-Headers "Content-Type, X-System"

| Header | Protection | |--------|-----------| | X-Frame-Options: SAMEORIGIN | Prevents clickjacking by blocking iframe embedding from other origins | | X-Content-Type-Options: nosniff | Prevents MIME-type sniffing attacks | | X-XSS-Protection: 1; mode=block | Enables browser-level XSS filter and blocks the page if an attack is detected | | Referrer-Policy: no-referrer | Prevents referrer leakage to third-party URLs | | Strict-Transport-Security | Forces HTTPS for 1 year including subdomains (HSTS) | | Access-Control-Allow-Headers | Restricts allowed CORS headers to only what the framework needs |

File Access Restrictions

<FilesMatch "^\.env$">
    Require all denied
</FilesMatch>

<FilesMatch "\.system/.*\.log$">
    Require all denied
</FilesMatch>

<FilesMatch "^\.system/storage/.*$">
    Require all denied
</FilesMatch>

These rules ensure that even if a misconfiguration allows directory browsing, sensitive files can never be served to the public.

Server Fingerprint Removal

Header unset X-Powered-By
ServerSignature Off
Options -Indexes

Removes PHP version information from response headers and disables Apache's "Powered by" signature - making it harder for attackers to fingerprint your stack.

HTTP Method Restriction

<LimitExcept GET POST PUT DELETE>
    Require all denied
</LimitExcept>

Blocks non-standard HTTP methods (OPTIONS, TRACE, CONNECT, etc.) that are commonly used in reconnaissance and exploit attempts.

URL Routing Rules

RewriteEngine on
RewriteRule ^favicon\.ico$ /.assets/logo.png [L]
RewriteRule ^robots\.txt$ /.assets/robots.txt [L]
RewriteRule ^sitemap\.xml$ /.assets/sitemap.xml [L]
RewriteRule ^assets/(.*)$ /.assets/$1 [L]

# Allow static asset files
RewriteCond %{REQUEST_URI} ^/.assets/.*\.(css|js|svg|mp4|ogg|mp3|jpeg|jpg|png|gif|ico|webp|xml|txt|json|csv)$ [NC]
RewriteRule .* - [L]

# Route everything else through PHP
RewriteRule ^(.*)$ .system/app.php [L,QSA]

All non-static requests are routed through .system/app.php, giving the framework complete control over routing, access checking and response handling.

Request Size Limit

SetEnv CONTENT_LENGTH 2

Limits request body size to 2 MB by default. Adjust this value in .htaccess if your application needs to handle larger file uploads.

Editing HTAccess

The .htaccess file is generated once during phpshift new and is not automatically regenerated. Edit it manually to:

After editing, test your changes with Apache's config test:

C:/xampp/apache/bin/httpd.exe -t

Rate Limiting

PHPShift's framework engine includes built-in rate limiting at two levels: per-session (ID rate) and per-IP (IP rate). These are configured in .htaccess via environment variables read by .system/app.php.

Configuration Variables

# Request body size limit (MB)
SetEnv CONTENT_LENGTH 2

# Session lock duration after rate limit hit (seconds)
SetEnv LOCK_TIME 30

# Per-session rate: time window (seconds)
SetEnv IDR_PERIOD 10

# Per-session rate: max requests per window
SetEnv IDR_AMOUNT 10

# Per-IP rate: time window (seconds)
SetEnv IPR_PERIOD 60

# Per-IP rate: max requests per window
SetEnv IPR_AMOUNT 200

How It Works

ID Rate (Session-Level)

Tracks requests per session identifier. If a single user session makes more than IDR_AMOUNT requests within IDR_PERIOD seconds, the session is locked for LOCK_TIME seconds.

Default: max 10 requests per 10 seconds per session. Locks for 30 seconds on violation.

Use case: protects against AJAX-heavy pages accidentally hammering the server and catches scripted abuse using a stolen session.

IP Rate (IP-Level)

Tracks requests per client IP address. If a single IP makes more than IPR_AMOUNT requests within IPR_PERIOD seconds, further requests from that IP are temporarily blocked.

Default: max 200 requests per 60 seconds per IP.

Use case: protects against scraping, brute force login attempts and DDoS from a single source.

Tuning for Your Application

The defaults are conservative. For applications with heavy front-end JavaScript activity (many App.call() requests per page), you may need to increase IDR_AMOUNT or IDR_PERIOD:

# Allow more requests for a data-heavy dashboard
SetEnv IDR_PERIOD 10
SetEnv IDR_AMOUNT 30

For public APIs that expect high volume from legitimate clients:

SetEnv IPR_PERIOD 60
SetEnv IPR_AMOUNT 1000

LOCK_TIME

When a session hits the ID rate limit, it is locked for LOCK_TIME seconds. Legitimate users experience a brief pause before they can make requests again. Scripted attackers face a compounding delay.

File Upload Size

CONTENT_LENGTH sets the maximum allowed request body in megabytes. The framework rejects requests exceeding this size before processing.

For pages with file uploads, increase this to match your expected maximum file size:

SetEnv CONTENT_LENGTH 10

Editing Rate Limits

Open .htaccess in your project root and adjust the SetEnv values. Changes take effect immediately - no Apache restart needed for .htaccess directives (as long as AllowOverride All is set in your virtual host configuration).

Development Loop

PHPShift's core workflow is a tight feedback loop: describe what you want, review the AI's output, confirm or retry. Understanding this loop helps you work efficiently and avoid frustration when output isn't quite right the first time.

The Loop

1. Select a skill from the menu
2. Describe your task in plain language
3. PHPShift collects project context and sends it to the AI
4. AI generates structured file output
5. Files are written, DB changes staged
6. PHPShift shows you the result
7. You choose: Yes / Redo / No

The Three Outcomes

Yes - Keep Changes

The files remain on disk, database changes are committed (DB.clear()) and you're offered a Git commit prompt. This finalizes the skill run.

Redo - Adjust and Retry

All changes roll back (files restored to pre-skill state, database reverted via DB.rollback()). PHPShift asks you to refine your description:

What would you like to change about your request?

You can add clarifying detail, correct a misunderstanding, or specify what was wrong with the previous attempt. The skill runs again with your updated description - often the AI gets it right on the second pass because it now has more specific guidance.

No - Discard Entirely

All changes roll back completely and you return to the main skill menu. No trace of the attempt remains.

Writing Effective Task Descriptions

The quality of AI output is directly tied to the quality of your description. Effective descriptions include:

Weak Example

Add a login page

Strong Example

Create a public login page with email and password fields, client-side 
validation for email format, a "remember me" checkbox and a link to 
a password reset flow. On successful login, redirect to /dashboard. 
On failure, show an inline error message without page reload. 
Match the styling of the existing welcome page.

Iterating Across Multiple Skill Runs

Complex features often require multiple skill invocations:

1. Create > Page (basic structure)
2. Edit > Page (add specific interactive feature)
3. Edit > Page (refine styling)
4. Create > Translation (add language support)

Each run benefits from full project context, so the AI stays consistent across iterations even when you're building incrementally.

When to Start Fresh vs. Edit

If a page has accumulated many small edits and feels inconsistent, consider Render > Page to regenerate it cleanly from its readme.md description, rather than continuing to patch with Edit > Page.

Patch System

The patch system is what makes PHPShift's AI generation safe to experiment with. Every skill run is wrapped in a snapshot-and-rollback mechanism covering both filesystem and database changes, so a bad AI response never leaves your project in a broken state.

Why It Exists

AI-generated code isn't always perfect on the first try. Without a safety net, a flawed generation could overwrite working files or insert bad data into your database with no easy way back. The patch system makes every skill run fully reversible.

How File Patching Works

Before a skill writes any files:

  1. PHPShift identifies which files/folders the skill is about to touch
  2. Current contents (or absence) of those paths are recorded in memory
  3. The skill executes and writes new files
  4. If you choose Redo or No, the original state is restored exactly:
  5. Modified files are reverted to their prior content
  6. New files that didn't exist before are deleted
  7. Deleted files (in Delete skills) are restored

How Database Patching Works

The Python DB module provides three key methods:

This means a db.sql migration that creates a table, inserts data, or alters a schema can be completely undone if you're not happy with the accompanying code.

What Gets Patch-Tracked

| Category | Tracked | |----------|---------| | Page files (html/css/js/php/readme) | Yes | | API files | Yes | | Cron files | Yes | | Database schema changes | Yes | | .access file changes | Yes | | .env new variable additions | Yes | | Composer package installations | Yes (uninstall on rollback) | | Git commits | No - commits happen only after final confirmation |

What Is Not Rollback-Safe

Practical Implications

Because of the patch system, you can be liberal with Redo. If a generated page is close but not quite right, don't manually fix it - describe the correction and let the AI regenerate. The rollback ensures no half-finished, inconsistent state accumulates from failed attempts.

Manual Recovery

If you ever need to manually verify rollback was clean, check your Git status - since uncommitted changes from a rejected skill run should leave your working directory exactly as it was before the skill started (assuming you commit after every accepted change, which PHPShift encourages).

Git Integration

PHPShift treats Git as a first-class part of the development workflow. Every confirmed skill run offers an immediate commit opportunity, keeping your history granular and meaningful without requiring you to leave the terminal.

Git Initialization

During phpshift new, you're asked whether to initialize a Git repository. If yes, PHPShift runs git init and creates an initial .gitignore that excludes:

.env
.system/vendor/
Space/*.log
*.local
node_modules/

Commit Prompt After Every Skill

When you confirm a skill's output (select Yes), PHPShift immediately asks:

Want to commit these changes?

If you confirm, you're prompted for a commit message - PHPShift can suggest one based on the skill and your task description, or you can write your own.

git add .
git commit -m "Add user dashboard page with task stats"

Push Prompt

After committing, if a remote is configured, PHPShift asks:

Want to push to remote?

Confirming runs git push against the current branch's tracked remote.

Why Commit After Every Skill

This pattern produces a clean, readable commit history where each commit corresponds to one logical AI-generated change - a new page, an edit, a translation addition. This makes it easy to:

Using Read > Git for Everything Else

The automatic commit/push flow handles the common case. For everything else - branching, merging, diffing, resetting, configuring remotes - use the Read > Git skill, which translates natural language into the appropriate Git command. See AI Skills → Read → Git for details.

Recommended Branching Strategy

While PHPShift doesn't enforce a specific Git workflow, a simple effective pattern for AI-paired development is:

  1. Work on main for small, low-risk changes (the patch system already protects you from bad generations)
  2. Use Read > Git to create a feature branch for larger multi-skill features
  3. Merge back to main once the feature is complete and tested

.gitignore Maintenance

If your generated code introduces new sensitive files or build artifacts, update .gitignore manually or via Read > Git:

Add a .gitignore rule to exclude the new uploads/ directory

Translations

PHPShift's translation system makes internationalizing a PHP project a one-step AI operation instead of a manual, error-prone process of touching every layer of the stack by hand.

The Translation Workflow

1. Build your page in your primary language (usually English)
2. Run Create > Translation, specify the target language
3. AI updates HTML, CSS, JS and PHP to support the new language
4. AI generates the Space/lng.{lang}.json file
5. Repeat for additional languages as needed

What Gets Touched

| Layer | Change | |-------|--------| | page.html | <translation languages="en,ka"> tag added; translate="key" attributes on text elements | | style.css | Language-switcher UI styles added | | script.js | Hardcoded strings wrapped in App.lng(key, defaultText, vars) | | code.php | Hardcoded strings wrapped in App::lng(key, defaultText, vars) | | Space/lng.{lang}.json | New file with all translated key-value pairs |

The Translation Tag

The <translation> tag tells the framework which languages a page supports and renders a language switcher UI:

<translation languages="en,ka,de"></translation>

The framework reads the visitor's preferred language (from a cookie, URL parameter, or browser header) and serves the matching Space/lng.{lang}.json values wherever translate attributes or lng() calls appear.

Static vs. Dynamic Translations

Static (HTML):

<h1 translate="page_title">Dashboard</h1>

Dynamic (JavaScript):

const msg = App.lng('items_count', '{count} items found', {count: total});

Dynamic (PHP):

$subject = App::lng('email_subject', 'Welcome, {name}!', ['name' => $username]);

The {variable} placeholder syntax works consistently across both JS and PHP lng() calls.

Translation File Format

{
    "page_title": "მთავარი გვერდი",
    "items_count": "{count} ნივთი ნაპოვნია",
    "email_subject": "კეთილი იყოს თქვენი მობრძანება, {name}!"
}

Adding Languages Incrementally

You don't need to translate everything at once. Run Create > Translation per page, per language, as needed. The skill detects existing translation infrastructure on a page and extends it rather than duplicating work.

Updating Translations

When you add new features to an already-translated page (via Edit > Page), new hardcoded strings may appear without translation keys. Run Edit > Translation to scan for and translate any newly introduced text.

Removing a Language

Use Delete > Translation to remove a language's lng.*.json file. Note that this does not automatically strip the language from <translation languages="..."> tags across pages - follow up with Edit > Page if you want that cleanup.

Cron Management

PHPShift manages cron job execution during local development through a Python background thread and provides the scaffolding needed for production cron setup. This page covers the operational side of working with crons day to day.

Starting and Stopping Crons in Development

When you run phpshift start and cron files exist in Crons/, you're asked:

Want to start cron jobs?

If you confirm, a background Python thread starts, calling:

php cron -auto

once every 60 seconds for the lifetime of your session.

You can also control this manually from the skill menu at any time:

More > StartCrons   - Start the background cron thread
More > StopCrons    - Stop the background cron thread

The menu dynamically shows the relevant option (Start vs Stop) based on current thread state.

How -auto Mode Works

The cron entry point script, when called with -auto, iterates every .php file in Crons/ and executes each one. Each cron file contains its own internal time-check guard (e.g., if (date('H:i') !== '00:00') exit;), so calling all crons every minute is safe - only the ones whose schedule matches the current time actually perform work.

Manual Single-Cron Execution

To test a specific cron job without waiting for its schedule or running the full auto cycle:

php cron sendDigest

This runs Crons/sendDigest.php directly, ignoring its internal time-check guard - useful for debugging.

Cron Output and Logging

Cron jobs typically log their activity to files in Space/:

file_put_contents(__DIR__ . '/../Space/digest.log', date('Y-m-d H:i:s') . " - Sent to " . count($users) . " users\n", FILE_APPEND);

Use Read > Log to have the AI analyze these logs and surface issues without manually scanning through raw text.

Production Cron Setup

PHPShift's background thread is a development convenience only - it does not run when PHPShift's CLI is closed. For production, configure a real system cron job on your server:

# crontab -e
* * * * * php /var/www/myapp/cron -auto >> /var/www/myapp/Space/cron-system.log 2>&1

This mirrors the development behavior: called every minute, each job self-determines whether it's time to run.

Common Cron Patterns

| Pattern | Guard | |---------|-------| | Every minute | (no guard) | | Every 5 minutes | if ((int)date('i') % 5 !== 0) exit; | | Hourly | if (date('i') !== '00') exit; | | Daily at specific time | if (date('H:i') !== '03:00') exit; | | Weekly on a day | if (date('D H:i') !== 'Mon 08:00') exit; | | Monthly on a date | if (date('d H:i') !== '01 00:00') exit; |

Debugging Cron Issues

  1. Check Space/*.log files for output via Read > Log
  2. Run the cron manually: php cron {filename}
  3. Verify the database schema the cron depends on hasn't changed unexpectedly
  4. Confirm More > StartCrons thread is actually running if testing live auto-execution