diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..047604a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,7 @@
+BasedOnStyle: LLVM
+UseTab: Always
+TabWidth: 4
+IndentWidth: 4
+ColumnLimit: 100
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..92c3c8e
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,12 @@
+Checks: >
+ clang-diagnostic-*,
+ clang-analyzer-*,
+ bugprone-*,
+ -bugprone-easily-swappable-parameters,
+ performance-*,
+ readability-*,
+ -readability-magic-numbers,
+ -readability-function-cognitive-complexity,
+ -readability-identifier-length,
+ -readability-braces-around-statements
+HeaderFilterRegex: '^(src|include)/.*'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..a705607
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,36 @@
+name: C CI
+
+on:
+ push:
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ build-and-test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y build-essential clang libcmocka-dev
+ sudo apt-get install -y build-essential clang clang-format clang-tidy libcmocka-dev bear
+
+ - name: Build
+ run: make CC=gcc
+
+ - name: Run tests
+ run: make test
+
+ - name: Check code formatting
+ run: |
+ find src/ -name '*.c' -o -name '*.h' | xargs clang-format --dry-run -Werror
+
+ - name: Generate compile_commands.json
+ run: bear -- make
+
+ - name: Static analysis
+ run: |
+ find src/ -name '*.c' | xargs clang-tidy --quiet
diff --git a/Makefile b/Makefile
index e69de29..c21ba06 100644
--- a/Makefile
+++ b/Makefile
@@ -0,0 +1,86 @@
+CC = gcc
+CFLAGS = -std=c11 -Wall -Wextra -O2 -D_POSIX_C_SOURCE=200809L \
+ -Iinclude -Ithird_party/stb -fopenmp -pthread
+CFLAGS_FAST = $(CFLAGS) -O3 -march=native
+CFLAGS_TEST = -std=c11 -Wall -Wextra -O0 -g -D_POSIX_C_SOURCE=200809L \
+ -Iinclude -Ithird_party/stb -fopenmp -pthread
+LDFLAGS = -lm -fopenmp -pthread
+TARGET = conv
+
+VPATH = src src/lib benchmarks
+
+SRCS = main.c conv.c cli.c filters.c imgio.c pipeline.c queue.c
+OBJS = $(SRCS:.c=.o)
+
+BENCH_DIR = benchmarks
+BENCH_BIN = conv_bench
+
+LIB_OBJS = conv.o cli.o filters.o imgio.o pipeline.o queue.o
+TEST_SRC = tests/test_conv.c
+TEST_BIN = test_runner
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+bench_conv.o: src/lib/conv.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+bench_filters.o: src/lib/filters.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+bench_imgio.o: src/lib/imgio.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+bench_pipeline.o: src/lib/pipeline.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+bench_queue.o: src/lib/queue.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+$(BENCH_DIR)/bench_main.o: $(BENCH_DIR)/bench_main.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+$(BENCH_DIR)/benchmark.o: $(BENCH_DIR)/benchmark.c
+ $(CC) $(CFLAGS_FAST) -c $< -o $@
+
+$(BENCH_BIN): $(BENCH_DIR)/bench_main.o $(BENCH_DIR)/benchmark.o \
+ bench_conv.o bench_filters.o \
+ bench_imgio.o bench_pipeline.o bench_queue.o
+ $(CC) $(CFLAGS_FAST) $^ -o $@ $(LDFLAGS)
+
+bench: $(BENCH_BIN)
+ mkdir -p results
+ ./$(BENCH_BIN) conv > results/bench.csv
+ @echo "Done: results/bench.csv"
+
+bench_pipeline: $(BENCH_BIN)
+ mkdir -p results
+ ./$(BENCH_BIN) pipeline > results/bench_pipeline.csv
+ @echo "Done: results/bench_pipeline.csv"
+
+bench_all: bench bench_pipeline
+ python3 $(BENCH_DIR)/plot.py results/bench.csv results/bench_pipeline.csv
+ @echo "Plots saved to results/"
+
+test: $(TEST_BIN)
+ ./$(TEST_BIN)
+
+$(TEST_BIN): $(LIB_OBJS) $(TEST_SRC)
+ $(CC) $(CFLAGS_TEST) $^ -o $@ -lm -lcmocka
+
+results:
+ mkdir -p results
+
+clean:
+ rm -f $(TARGET) $(BENCH_BIN) $(OBJS) \
+ $(BENCH_DIR)/bench_main.o $(BENCH_DIR)/benchmark.o \
+ bench_conv.o bench_filters.o bench_imgio.o \
+ bench_pipeline.o bench_queue.o $(TEST_BIN)
+ rm -rf results *.o
+
+.PHONY: all test bench bench_pipeline bench_all clean results
diff --git a/README.md b/README.md
index e69de29..2b8e8b7 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,72 @@
+# Image Convolution
+
+Simple CLI tool for applying convolution filters to images.
+Supports single-image processing and a dynamic pipeline for batch processing.
+
+## Build & Run
+
+```bash
+make # build
+make test # run unit tests
+make bench # benchmarks for parallel convolution → results/bench.csv
+make bench_pipeline # benchmarks for pipeline convolution → results/bench_pipeline.csv
+make bench_all # run all benchmarks & auto-generate plots
+```
+
+## Usage
+
+**Single image:**
+
+```bash
+./conv