diff --git a/src/smarttools/web/docs_content.py b/src/smarttools/web/docs_content.py new file mode 100644 index 0000000..e1c86da --- /dev/null +++ b/src/smarttools/web/docs_content.py @@ -0,0 +1,400 @@ +"""Documentation content for SmartTools web UI. + +This module contains the actual documentation text that gets rendered +on the /docs pages. Content is stored as markdown-ish HTML for simplicity. +""" + +DOCS = { + "getting-started": { + "title": "Getting Started", + "description": "Learn how to install SmartTools and create your first AI-powered CLI tool", + "content": """ +
SmartTools lets you build custom AI-powered CLI commands using simple YAML configuration. +Create tools that work with any AI provider and compose them like Unix pipes.
+ +SmartTools is a lightweight personal tool builder that lets you:
+Get up and running in under a minute:
+ +# Install SmartTools
+pip install smarttools
+
+# Create your first tool interactively
+smarttools create
+
+# Or install a tool from the registry
+smarttools registry install official/summarize
+
+# Use it!
+cat article.txt | summarize
+
+Each tool is a YAML file that defines:
+Here's a simple example:
+name: summarize
+version: "1.0.0"
+description: Summarize text using AI
+
+arguments:
+ - flag: --max-length
+ variable: max_length
+ default: "200"
+ description: Maximum summary length in words
+
+steps:
+ - type: prompt
+ provider: claude
+ prompt: |
+ Summarize the following text in {max_length} words or less:
+
+ {input}
+ output_var: summary
+
+output: "{summary}"
+
+SmartTools requires Python 3.8+ and works on Linux, macOS, and Windows.
+ +The simplest way to install SmartTools:
+pip install smarttools
+
+Or with pipx for isolated installation:
+pipx install smarttools
+
+smarttools --version
+smarttools --help
+
+SmartTools needs at least one AI provider configured. The easiest is Claude CLI:
+ +# Install Claude CLI (if you have an Anthropic API key)
+pip install claude-cli
+
+# Or use OpenAI
+pip install openai
+
+# Configure your provider
+smarttools config
+
+SmartTools installs wrapper scripts to ~/.local/bin/. Make sure this is in your PATH:
# Add to ~/.bashrc or ~/.zshrc
+export PATH="$HOME/.local/bin:$PATH"
+
+To contribute or modify SmartTools:
+git clone https://gitea.brrd.tech/rob/SmartTools.git
+cd SmartTools
+pip install -e ".[dev]"
+""",
+ "headings": [
+ ("pip-install", "Install with pip"),
+ ("verify", "Verify Installation"),
+ ("configure-provider", "Configure a Provider"),
+ ("wrapper-scripts", "Wrapper Scripts Location"),
+ ("development-install", "Development Installation"),
+ ],
+ },
+
+ "first-tool": {
+ "title": "Your First Tool",
+ "description": "Create your first SmartTools command step by step",
+ "parent": "getting-started",
+ "content": """
+Let's create a simple tool that explains code. You'll learn the basics of tool configuration.
+ +Run the interactive creator:
+smarttools create
+
+Or create the file manually at ~/.smarttools/explain/config.yaml:
name: explain
+version: "1.0.0"
+description: Explain code or concepts in simple terms
+category: code
+
+arguments:
+ - flag: --level
+ variable: level
+ default: "beginner"
+ description: "Explanation level: beginner, intermediate, or expert"
+
+steps:
+ - type: prompt
+ provider: claude
+ prompt: |
+ Explain the following in simple terms suitable for a {level}:
+
+ {input}
+
+ Be concise but thorough. Use examples where helpful.
+ output_var: explanation
+
+output: "{explanation}"
+
+# Explain some code
+echo "def fib(n): return n if n < 2 else fib(n-1) + fib(n-2)" | explain
+
+# Explain for an expert
+cat complex_algorithm.py | explain --level expert
+
+Each argument becomes a CLI flag. The variable name is used in templates:
arguments:
+ - flag: --level # CLI flag: --level beginner
+ variable: level # Use as {level} in prompts
+ default: "beginner" # Default if not specified
+
+Steps run in order. Each step can be a prompt or Python code:
+steps:
+ - type: prompt
+ provider: claude # Which AI to use
+ prompt: "..." # The prompt template
+ output_var: result # Store response in {result}
+
+The output template formats the final result:
+output: "{explanation}" # Print the explanation variable
+
+Share your tools with the community by publishing to the SmartTools Registry.
+ +Make sure your tool has:
+name and descriptionversion (semver format: 1.0.0)README.md file with usage examplesRegister at the registry to get your publisher namespace.
+ +# Navigate to your tool directory
+cd ~/.smarttools/my-tool/
+
+# First time: enter your token when prompted
+smarttools registry publish
+
+# Dry run to validate without publishing
+smarttools registry publish --dry-run
+
+Published versions are immutable. To update a tool:
+config.yamlsmarttools registry publishSmartTools works with any AI provider that has a CLI interface. Configure providers in
+~/.smarttools/providers.yaml.
Create or edit ~/.smarttools/providers.yaml:
providers:
+ - name: claude
+ command: "claude -p"
+
+ - name: openai
+ command: "openai-cli"
+
+ - name: ollama
+ command: "ollama run llama2"
+
+ - name: mock
+ command: "echo '[MOCK RESPONSE]'"
+
+Specify the provider in your step:
+steps:
+ - type: prompt
+ provider: claude # Uses the "claude" provider from config
+ prompt: "..."
+ output_var: response
+
+# Install
+pip install claude-cli
+
+# Configure with your API key
+export ANTHROPIC_API_KEY="sk-ant-..."
+
+# providers.yaml
+providers:
+ - name: claude
+ command: "claude -p"
+
+# Install
+pip install openai-cli
+
+# Configure
+export OPENAI_API_KEY="sk-..."
+
+# Install Ollama from ollama.ai
+# Pull a model
+ollama pull llama2
+
+# providers.yaml
+providers:
+ - name: ollama
+ command: "ollama run llama2"
+
+Use the mock provider to test tools without API calls:
+providers:
+ - name: mock
+ command: "echo 'This is a mock response for testing'"
+
+| Provider | +Best For | +Cost | +
|---|---|---|
| Claude | +Complex reasoning, long context | +Pay per token | +
| OpenAI | +General purpose, fast | +Pay per token | +
| Ollama | +Privacy, offline use | +Free (local) | +
Documentation for {escape(current)} is coming soon.
", - headings=[], - parent=None, - ) + + # Get content from docs_content module + doc = get_doc(current) + if doc: + page = SimpleNamespace( + title=doc["title"], + description=doc["description"], + content_html=Markup(doc["content"]), + headings=doc.get("headings", []), + parent=doc.get("parent"), + ) + else: + page = SimpleNamespace( + title=_title_case(current), + description="SmartTools documentation", + content_html=Markup(f"Documentation for {escape(current)} is coming soon.
"), + headings=[], + parent=None, + ) + show_ads = current_app.config.get("SHOW_ADS", False) return render_template( "pages/docs.html", @@ -538,3 +546,92 @@ def forgot_password(): title="Reset Password", body="Password resets are not available yet. Please contact support if needed.", ) + + +@web_bp.route("/robots.txt", endpoint="robots") +def robots(): + """Serve robots.txt - we welcome all crawlers including AI.""" + from flask import send_from_directory + return send_from_directory( + web_bp.static_folder, + "robots.txt", + mimetype="text/plain" + ) + + +@web_bp.route("/sitemap.xml", endpoint="sitemap") +def sitemap(): + """Generate dynamic sitemap.xml with all public pages and tools.""" + from flask import Response + from datetime import datetime + + conn = connect_db() + try: + tools = query_all( + conn, + """ + WITH latest AS ( + SELECT owner, name, MAX(id) AS max_id + FROM tools + WHERE version NOT LIKE '%-%' + GROUP BY owner, name + ) + SELECT t.owner, t.name, t.published_at + FROM tools t + JOIN latest ON t.owner = latest.owner AND t.name = latest.name AND t.id = latest.max_id + ORDER BY t.published_at DESC + """, + [], + ) + tools = [dict(row) for row in tools] + finally: + conn.close() + + base_url = request.url_root.rstrip("/") + today = datetime.utcnow().strftime("%Y-%m-%d") + + # Static pages + static_pages = [ + ("/", "1.0", "daily"), + ("/tools", "0.9", "daily"), + ("/docs", "0.8", "weekly"), + ("/docs/getting-started", "0.8", "weekly"), + ("/docs/installation", "0.7", "weekly"), + ("/docs/first-tool", "0.7", "weekly"), + ("/docs/publishing", "0.7", "weekly"), + ("/docs/providers", "0.7", "weekly"), + ("/tutorials", "0.7", "weekly"), + ("/about", "0.5", "monthly"), + ("/community", "0.5", "weekly"), + ("/donate", "0.4", "monthly"), + ("/privacy", "0.3", "monthly"), + ("/terms", "0.3", "monthly"), + ] + + xml_parts = [''] + xml_parts.append('