This file defines the development rules, architecture standards, safety requirements, and agent behavior for this project.
All AI coding agents working in this repository must read this file before making changes.
The primary development environment is:
VBScript provides limited compile-time validation, weak typing, limited object-oriented features, and minimal runtime safeguards.
AI agents must compensate for these limitations through:
The AI agent must behave as more than a code generator.
It must act as:
The agent must actively look for problems that VBScript itself may not catch.
When instructions conflict, follow this priority:
Never weaken security, validation, or data integrity simply to match poor legacy code.
If legacy code conflicts with these standards, preserve compatibility where required while gradually improving the implementation.
Every ASP, VBS, and applicable WSC script must use:
Option Explicit
No undeclared variables are permitted.
Before finishing a task, inspect all changed code for undeclared or misspelled identifiers.
All variables must be explicitly declared using an appropriate declaration:
Dim
Private
Public
Const
Avoid excessive variable reuse.
Prefer descriptive names.
Bad:
Dim x
Dim y
Better:
Dim customerId
Dim orderTotal
VBScript uses Variants extensively.
Do not assume that a value has the expected type.
External values must be normalized near application boundaries.
Use explicit conversion where appropriate:
CStr()
CLng()
CInt()
CDbl()
CBool()
CDate()
Never convert unvalidated input blindly.
Validate first when conversion can fail.
These are different states and must not be treated as equivalent.
Use:
IsNull(value)
IsEmpty(value)
object Is Nothing
Database values may contain Null.
Uninitialized Variants may contain Empty.
Object references may contain Nothing.
Code must explicitly account for the state that is expected.
Do not rely on accidental VBScript coercion.
Treat all external input as untrusted, including:
External data must pass through:
Input
↓
Validation
↓
Normalization
↓
Authorization
↓
Business Logic
Never pass raw Request values directly into database or business operations.
User-controlled data must never be concatenated into SQL.
Prohibited:
sql = "SELECT * FROM Users WHERE Email = '" & email & "'"
Required:
Set cmd = Server.CreateObject("ADODB.Command")
Set cmd.ActiveConnection = conn
cmd.CommandText = _
"SELECT UserId, Email " & _
"FROM Users " & _
"WHERE Email = ?"
cmd.Parameters.Append _
cmd.CreateParameter("@Email", adVarWChar, adParamInput, 255, email)
Use parameters for:
When identifiers such as table names or sort columns must be dynamic, they cannot normally be parameterized.
In such cases, use a whitelist.
Example:
Select Case sortField
Case "Name", "CreatedDate", "Status"
' allowed
Case Else
sortField = "CreatedDate"
End Select
Never accept arbitrary table names, column names, or SQL fragments from users.
HTML output must be encoded by default.
Prefer:
Server.HTMLEncode(value)
or a centralized helper such as:
Function H(value)
If IsNull(value) Then
H = ""
Else
H = Server.HTMLEncode(CStr(value))
End If
End Function
Raw HTML output should only be used when the value is explicitly trusted and intentionally contains HTML.
Do not assume database data is safe to output without encoding.
Broad use of:
On Error Resume Next
is prohibited.
It may only be used around the smallest practical operation requiring error interception.
Required pattern:
On Error Resume Next
Set rs = cmd.Execute()
If Err.Number <> 0 Then
errorNumber = Err.Number
errorDescription = Err.Description
Err.Clear
On Error GoTo 0
LogError errorNumber, errorDescription
Err.Raise _
vbObjectError + 1000, _
"CustomerRepository.GetCustomer", _
"Database operation failed."
End If
On Error GoTo 0
Always restore normal error handling.
Do not silently ignore:
Failures must either:
The preferred application flow is:
HTTP Request
↓
Router
↓
Controller
↓
Service
↓
Repository
↓
Database
Views receive prepared data from controllers or ViewModels.
Controllers may:
Controllers must not:
Keep controllers thin.
Services contain application and business logic.
Services may:
Services must not:
Prefer dependency injection through explicit initialization.
Repositories own persistence logic.
Repositories may:
Repositories must not:
Views may:
Views must not:
Encode dynamic output by default.
Models should represent application or domain data.
ViewModels should represent data specifically prepared for a view.
Do not pass ADODB.Recordset objects directly into views unless the existing architecture explicitly requires it and refactoring is not currently practical.
Prefer converting recordsets into application-friendly structures.
VBScript does not provide modern dependency injection.
Use explicit initialization.
Example:
Class CustomerService
Private m_repository
Private m_logger
Public Sub Init(repository, logger)
Set m_repository = repository
Set m_logger = logger
End Sub
End Class
Dependencies should be visible.
Avoid hidden global dependencies where practical.
VBScript has limited inheritance capabilities.
Prefer composition.
Instead of designing deep pseudo-inheritance systems, compose objects from smaller collaborators.
Example:
CustomerService
├── CustomerRepository
├── CustomerValidator
└── Logger
VBScript cannot formally declare interfaces.
When interchangeable implementations are needed, define a documented contract.
Example:
IUserRepository
Required members:
GetById(userId)
GetByEmail(email)
Create(user)
Update(user)
Delete(userId)
Agents must verify that implementations satisfy documented contracts.
Use Class_Initialize only for safe initialization that requires no external dependencies.
Use an explicit method such as:
Public Sub Init(...)
for dependency injection.
Classes should not secretly fetch dependencies from globals when explicit injection is practical.
Avoid storing custom COM objects, recordsets, service instances, or application classes in:
Session
Application
Prefer primitive values:
Session("UserId") = CLng(userId)
Session("Username") = CStr(username)
Use Application state carefully and protect shared writes appropriately.
Explicitly close database resources.
Example:
If Not rs Is Nothing Then
If rs.State <> 0 Then
rs.Close
End If
Set rs = Nothing
End If
Connections must also be closed when owned by the current operation.
Do not leave recordsets or connections open unnecessarily.
The project should clearly define who owns a database connection.
A method that opens a connection is normally responsible for closing it.
Do not close a connection owned by another component unless the contract explicitly states that responsibility.
Prefer small cohesive procedures.
Target guideline:
Function:
10–40 lines where practical
Class:
100–300 lines where practical
Controller:
preferably under 200 lines
These are guidelines, not absolute limits.
When code becomes difficult to understand, split it by responsibility.
Use consistent naming because VBScript is case-insensitive and offers limited compiler assistance.
Preferred examples:
customerId
customerName
orderRepository
customerService
isValid
hasPermission
Class names:
CustomerService
CustomerRepository
CustomerValidator
OrderController
Private fields may use:
m_repository
m_logger
m_customerId
Follow established project conventions if they are consistent and clear.
Prefer names that read naturally:
isValid
isActive
hasAccess
hasPermission
canDelete
shouldRetry
Avoid ambiguous names such as:
flag
value1
test
status2
Avoid unexplained magic values.
Bad:
If status = 4 Then
Better:
Const STATUS_COMPLETED = 4
Use constants or centralized configuration where appropriate.
Environment-specific settings must not be scattered throughout application code.
Centralize:
Secrets must not be committed to source control.
Important errors should be logged with useful context.
Prefer structured information such as:
Timestamp
RequestId
UserId if appropriate
Component
Operation
Error number
Error description
Relevant safe context
Never log:
Authentication answers:
Who is this user?
Authorization answers:
Is this user allowed to perform this operation?
They are not interchangeable.
Authorization must be enforced server-side.
Never rely solely on hidden buttons, JavaScript, or UI restrictions.
State-changing requests should use CSRF protection where practical.
This includes:
Do not perform destructive actions solely through unprotected GET requests.
Prefer:
GET → retrieve data
POST → create/change state
Avoid state-changing GET endpoints unless required by legacy compatibility.
Do not redirect to arbitrary user-provided URLs.
Validate redirects against:
Uploaded files must be treated as untrusted.
Validate:
Prevent path traversal.
Never construct filesystem paths directly from arbitrary user input.
Includes are dependencies, not architecture.
Avoid large global include chains.
Prefer explicit grouped includes such as:
/config
/framework
/app/controllers
/app/services
/app/repositories
/app/models
/app/views
Before adding a new include, check whether the functionality belongs in an existing component.
Before creating a utility function, search for an existing implementation.
Common shared helpers may include:
HtmlEncode
JsonEncode
JsonEscape
Nz
ToInteger
ToLong
ToBoolean
ToDate
ValidateEmail
ExecuteScalar
ExecuteNonQuery
Logger
UrlEncode
GenerateGuid
Do not create duplicate helpers with slightly different behavior.
Do not build complex JSON through unsafe string concatenation.
Use the project's JSON serializer or centralized JSON utilities.
Escape:
Ensure output is valid JSON.
Server-side validation is mandatory even when client-side validation exists.
JavaScript validation is for user experience.
VBScript validation is for correctness and security.
Never trust browser-side validation alone.
Every significant change should be evaluated for testability.
Where practical, create tests for:
Business logic should be separated from ASP globals so it can be tested independently.
When fixing a bug:
Do not patch symptoms repeatedly.
Before modifying code, the agent should:
For small changes, do this proportionally.
Before declaring work complete, review changed code for:
VBScript requires Set for object assignment.
Agents must specifically inspect object assignments.
Incorrect:
repo = New CustomerRepository
Correct:
Set repo = New CustomerRepository
This should be part of every static review.
VBScript functions return values by assigning to the function name.
Example:
Function AddNumbers(a, b)
AddNumbers = a + b
End Function
Agents must verify all execution paths return the expected value when a return value is required.
VBScript parameters are ByRef by default.
This can unintentionally mutate caller values.
Prefer explicitly declaring intent.
Use:
Function ValidateCustomer(ByVal customer)
when modification of the caller's variable is not intended.
Use ByRef intentionally.
VBScript procedure-call syntax can be confusing.
Agents must generate syntactically valid VBScript calls.
Be especially careful with:
CallCallPrefer simple consistent calling patterns.
Do not assume date string formats.
Prefer true Date values internally.
Validate and convert input explicitly.
Be aware of:
Use parameterized database values rather than embedding formatted date strings in SQL.
Do not assume values from Request are numeric.
Validate before conversion.
Example logic:
Read input
↓
Trim
↓
Check required/optional
↓
Validate numeric format
↓
Convert
Handle overflow and invalid values appropriately.
When mapping database records to models, define expected behavior for Null fields.
Do not allow arbitrary Null propagation unless the domain explicitly permits it.
Consider centralized helpers.
ASP Classic is synchronous.
Avoid unnecessary:
Watch for N+1 query patterns.
Prefer set-based SQL.
Caching may be used where appropriate but must have:
Never cache sensitive per-user data globally without proper separation.
ASP Application state can be shared across requests.
When modifying shared Application values, consider:
Application.Lock
Application.Unlock
Keep locked regions minimal.
When modifying legacy code:
Do not modernize code purely for style if it introduces unnecessary risk.
Refactoring should preserve observable behavior unless changing behavior is an explicit goal.
Separate:
behavior change
from:
structural cleanup
where practical.
When introducing:
update relevant documentation.
Do not leave important architectural knowledge only in source code.
This file is allowed to evolve.
Agents may propose or make updates to AGENTS.md when project experience reveals that the instructions are:
Self-improvement must be controlled.
Consider updating this file when:
Do not update this file for trivial one-time implementation details.
An agent must never silently weaken these core protections:
Changes affecting these protections require explicit justification.
Rules may be considered:
CORE
PROJECT
ADVISORY
TEMPORARY
CORE rules should rarely change.
Examples:
CORE:
SQL parameterization
Option Explicit
server-side authorization
output encoding
PROJECT:
folder structure
repository naming
routing conventions
ADVISORY:
function length guidelines
TEMPORARY:
migration-specific compatibility rules
When adding an important rule, identify its conceptual category if useful.
After fixing a significant bug, ask:
Could a rule have prevented this?
If yes:
Prefer systemic prevention over repeated manual correction.
If a code review repeatedly identifies the same problem, convert the feedback into:
The goal is continuous reduction of repeated mistakes.
Meaningful changes to AGENTS.md should be recorded below.
Keep entries concise.
Format:
YYYY-MM-DD
- Added rule:
- Reason:
Example:
2026-09-02
- Added explicit ByVal guidance.
- Reason: VBScript defaults to ByRef and accidental mutations were difficult to detect.
AGENTS.md should contain durable development knowledge.
Do not store:
Move specialized guidance into focused files when this file becomes too large.
As the project grows, agents may create focused guidance such as:
/docs/architecture.md
/docs/security.md
/docs/database.md
/docs/testing.md
/skills/asp-classic.md
/skills/adodb.md
/skills/security.md
/skills/testing.md
AGENTS.md remains the central index and policy authority.
Agents may create a new skill or focused guidance document when:
A new skill should state:
Purpose
When to use it
Inputs
Procedure
Rules
Validation
Common failure modes
Output expectations
When project behavior changes, update the existing relevant skill instead of creating a duplicate.
Before creating a new document, search for an existing location for that knowledge.
For major architectural changes, record concise rationale in the appropriate documentation.
Document:
Decision
Context
Alternatives
Reason selected
Consequences
Do not record private chain-of-thought.
Record only useful engineering rationale.
A task is not complete merely because the code runs.
A change is complete when appropriate checks have been performed for:
Correctness
Security
Architecture
Compatibility
Validation
Error handling
Resource cleanup
Testing
Documentation
Maintainability
Before finishing a coding task, answer internally:
[ ] Did I read the relevant instructions?
[ ] Did I inspect existing code before creating new code?
[ ] Did I preserve architecture boundaries?
[ ] Is all external input validated?
[ ] Is SQL parameterized?
[ ] Is dynamic HTML encoded?
[ ] Is authorization enforced server-side?
[ ] Are errors handled intentionally?
[ ] Are database resources cleaned up?
[ ] Are object assignments using Set?
[ ] Did I account for Null, Empty, and Nothing?
[ ] Did I account for ByRef behavior?
[ ] Did I avoid unnecessary global state?
[ ] Did I avoid duplicating utilities?
[ ] Did I update tests where appropriate?
[ ] Did I update documentation if a durable rule changed?
[ ] Did this task reveal something the agent rules should learn?
Do not fight VBScript.
Compensate for its weaknesses.
Prefer simple, explicit, understandable code over clever abstractions.
The desired result is:
Classic ASP simplicity
+
strict engineering discipline
+
AI-assisted static review
+
modern security practices
=
maintainable ASP Classic applications
2026-09-02
Powered by TurnKey Linux.